Android 版本更新(1)

本文介绍了移动应用的开发流程,包括SVN版本控制、Splash界面设计、版本号获取及应用更新机制。涵盖代码结构划分、JSON数据处理、下载与安装操作等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

svn

svn checkout
svn update
svn commit
svn add

student 
123

http://192.168.20.87/svn/Mobliesafe75

spalsh界面的作用

1 卖弄 logo界面 展示次数 品牌效应 
2 项目初始化  数据库copy    
3 提醒用户更新版本
4 广告的展示

小步快跑  一个月做出beta版app,抢占市场,一个星期更新一个版本,10版本积攒人气,11版本盈利

代码包结构划分方式

目的:方便后期维护和更新的项目

1.按照代码类型划分

2.按照业务类型划分
    业务模块比较独立
    黑马  办公软件   www.itheima.com
    教学模块  com.itheima.teach
    招生模块     com.itheima.student
    财务模块     com.itheima.money

spalsh界面搭建# (重点)

1.textview的阴影效果
    <!-- layout_centerInParent:在父控件的中间位置 
    shadow
    shadowColor : 设置阴影颜色
    shadowDx : 关于x轴的偏移量
    shadowRadius : 偏移的角度
    -->

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="版本号:1.0" 
        android:shadowColor="#ffff00"
        android:shadowDx="1"
        android:shadowDy="1"
        android:shadowRadius="2"
        />
2.去除标题栏
    1.在values目录的styles.xml文件中增加属性
        <!-- Application theme. -->
        <style name="AppTheme" parent="AppBaseTheme">
            <!-- 去除标题栏 -->
            <item name="android:windowNoTitle">true</item>
            <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        </style>
    2.在清单文件中的application中设置theme属性是我们工程的AppTheme
         android:theme="@style/AppTheme"

获取版本号# (重点)

id : 驼峰式命名:   控件类型_控件的所在位置_控件表示的逻辑内容

/**
 * 获取当前应用程序的版本号
 * @return
 */
private String getVersionName(){
    //包的管理者,获取清单文件中的所有信息
    PackageManager pm = getPackageManager();
    try {
        //根据包名获取清单文件中的信息,其实就是返回一个保存有清单文件信息的javabean
        //packageName :应用程序的包名
        //flags : 指定信息的标签,0:获取基础的信息,比如包名,版本号,要想获取权限等等信息,必须通过标签来指定,才能去获取
        //GET_PERMISSIONS : 标签的含义:处理获取基础信息之外,还会额外获取权限的信息
        //getPackageName() : 获取当前应用程序的包名
        PackageInfo packageInfo = pm.getPackageInfo(getPackageName(), 0);
        //获取版本号名称
        String versionName = packageInfo.versionName;
        return versionName;
    } catch (NameNotFoundException e) {
        //包名找不到的异常
        e.printStackTrace();
    }
    return null;
}

连接服务器

/**
 * 提醒用户更新版本
 */
private void update() {
    //1.连接服务器,查看是否有最新版本,  联网操作,耗时操作,4.0以后不允许在主线程中执行的,放到子线程中执行
    new Thread(){
        public void run() {
            try {
                //1.1连接服务器
                //1.1.1设置连接路径
                //spec:连接路径
                URL url = new URL("xxxxx");
                //1.1.2获取连接操作
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();//http协议,httpClient
                //1.1.3设置超时时间
                conn.setConnectTimeout(5000);//设置连接超时时间
                //conn.setReadTimeout(5000);//设置读取超时时间
                //1.1.4设置请求方式
                conn.setRequestMethod("GET");//post
                //1.1.5获取服务器返回的状态码,200,404,500
                int responseCode = conn.getResponseCode();
                if (responseCode == 200) {
                    //连接成功
                }else{
                    //连接失败
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        };
    }.start();
}

权限:<uses-permission android:name="android.permission.INTERNET"/>

数据封装形式# (重点)

1.xml
2.json
json封装形式:{"code":"2.0","apkurl":"xxxxx","des":"新版本上线了,快来下载吧!!!!"}

json : utf-8无bom格式  Notepad++
       editplus : utf-8 (选择)   utf-8+bom

解析json数据# (重点)

1.获取服务器返回的流信息
    //获取服务器返回的流信息
    InputStream in = conn.getInputStream();
2.将流信息转化成字符串
    public class StreamUtil {
        /**
         * 将流信息转化成字符串
         * @return
         * @throws IOException 
         */
        public static String parserStreamUtil(InputStream in) throws IOException{
            //字符流,读取流
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            //写入流
            StringWriter sw  = new StringWriter();
            //读写操作
            //数据缓冲区
            String str = null;
            while((str = br.readLine()) !=null){
                //写入操作
                sw.write(str);
            }
            //关流
            sw.close();
            br.close();
            return sw.toString();
        }
    }
3.解析json数据
    //将获取到的流信息转化成字符串
    String json = StreamUtil.parserStreamUtil(in);
    //解析json数据
    JSONObject jsonObject = new JSONObject(json);
4.获取数据
    //获取数据
    code = jsonObject.getString("code");
    apkurl = jsonObject.getString("apkurl");
    des = jsonObject.getString("des");

弹出对话框

1.因为在子线程不能更新主线程ui所以给handler发送一个,在handler中弹出对话框
    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case MSG_UPDATE_DIALOG:
                //弹出对话框
                showdialog();
                break;
            }
        };
    };
2.弹出对话框
    /**
     * 弹出对话框
     */
    protected void showdialog() {
        AlertDialog.Builder builder = new Builder(this);
        //设置对话框不能消失
        builder.setCancelable(false);
        //设置对话框的标题
        builder.setTitle("新版本:"+code);
        //设置对话框的图标
        builder.setIcon(R.drawable.ic_launcher);
        //设置对话框的描述信息
        builder.setMessage(des);
        //设置升级取消按钮
        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();//两种方式效果一样
        builder.show();
    }

对话框细节的处理

1.实现了取消按钮的操作
    builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            //1.隐藏对话框
            dialog.dismiss();
            //2.跳转到主界面
            enterHome();
        }
    });
2.处理了在跳转到主界面,从主界面点击返回键返回的时候,返回splash界面的问题,解决:在跳转的是将splash界面移出
    /**
     * 跳转到主界面
     */
    protected void enterHome() {
        Intent intent = new Intent(this,HomeActivity.class);
        startActivity(intent);
        //移出splash界面
        finish();
    }
3.处理对话框延迟显示的问题
    //处理连接外网连接时间的问题
    //在连接成功之后在去获取一个时间
    int endTime = (int) System.currentTimeMillis();
    //比较两个时间的时间差,如果小于两秒,睡两秒,大于两秒,不睡
    int dTime = endTime-startTime;
    if (dTime<2000) {
        //睡两秒钟
        SystemClock.sleep(2000-dTime);//始终都是睡两秒钟的时间
    }

下载操作# (重点)

/**
 * 3.下载最新版本
 */
protected void download() {
    HttpUtils httpUtils = new HttpUtils();
    //判断SD卡是否挂载
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        //url : 新版本下载的路径 apkurl
        //target : 保存新版本的目录
        //callback : RequestCallBack
        httpUtils.download(apkurl, "/mnt/sdcard/mobliesafe75_2.apk", new RequestCallBack<File>() {
            //现在成功调用的方法
            @Override
            public void onSuccess(ResponseInfo<File> arg0) {
                // TODO Auto-generated method stub

            }
            //下载失败调用的方法
            @Override
            public void onFailure(HttpException arg0, String arg1) {
                // TODO Auto-generated method stub

            }
            //显示当前下载进度操作
            //total : 下载总进度
            //current : 下载的当前进度
            //isUploading : 是否支持断点续传
            @Override
            public void onLoading(long total, long current, boolean isUploading) {
                super.onLoading(total, current, isUploading);
                //设置显示下载进度的textview可见,同时设置相应的下载进度
                tv_spalsh_plan.setVisibility(View.VISIBLE);//设置控件是否可见
                tv_spalsh_plan.setText(current+"/"+total);//110/200
            }

        });
    }
}

注意问题:
    1.修改apkurl地址
    2.增加sd操作权限
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    3.判断sd是否挂载
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {}
    4.生成2.0版本的apk
        工程的bin目录下去找
        a.将清单文件中的版本号改成2.0
        b.重新运行
        c.拷贝bin目录下的文件

安装新的apk# (重点)

/**
 * 4.安装最新的版本
 */
protected void installAPK() {
    /**
     *  <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="content" /> //content : 从内容提供者中获取数据  content://
            <data android:scheme="file" /> // file : 从文件中获取数据
            <data android:mimeType="application/vnd.android.package-archive" />
        </intent-filter>
     */
    Intent intent = new Intent();
    intent.setAction("android.intent.action.VIEW");
    intent.addCategory("android.intent.category.DEFAULT");
    //单独设置会相互覆盖
    /*intent.setType("application/vnd.android.package-archive");
    intent.setData(Uri.fromFile(new File("/mnt/sdcard/mobliesafe75_2.apk")));*/
    intent.setDataAndType(Uri.fromFile(new File("/mnt/sdcard/mobliesafe75_2.apk")), "application/vnd.android.package-archive");
    //在当前activity退出的时候,会调用之前的activity的onActivityResult方法
    //requestCode : 请求码,用来标示是从哪个activity跳转过来
    //ABC  a -> c    b-> c  ,c区分intent是从哪个activity传递过来的,这时候就要用到请求码
    startActivityForResult(intent, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    enterHome();
}

异常处理

根据不同的异常,采用不同方式处理,方便项目后期定位异常,便于解决维护异常

两种上下文的区别

1.getApplicationContext()  返回Context 
2.activity.this   代表的就是当前的activity,继承context,父类当中有的方法子类中一定有,子类中有的方法父类中不一定有,在用getApplicationContext()一定能使用activity.this,但是能用activity.this不一定能使用getApplicationContext()

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application  没有添加窗口,

在使用对话框的时候,必须告诉对话框,要挂载在那个activity,也是告诉对话框应用在那个activity中显示

在使用跟对话框相关的操作的时候必须使用activity.this不能使用getApplicationContext()

getContext() : 返回Context ,一般用在单元测试中或者是自定义控件,其实和getApplicationContext()一样操作

打包签名# (重点!!!!!)

只有打包签名过的应用才能上传应用市场上去

应用升级条件
    1.包名一致
    2.签名一致
微信  com.weixin
流氓程序  com.weixin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值