#手机卫士西安2期笔记#
##Day01##
#学习方法#
看代码 -> 看笔记 -> 看视频(2倍速)
#1.1svn版本控制# **
常见命令:
svn checkout
svn update
svn commit
svn add
user: student
password: 123
http://192.168.1.100/svn/mobilesafexian02
创建一个svn仓库?
打开VisualSVN Server-->选中respository右键,点击create New Respository-->最后copy一下仓库respository Name(仓库名称)和repostory URL(仓库地址)
仓库创建成功后,接着创建手机卫士这个工程,将工程和仓库关联起来
创建手机卫士时,
Application Name是app在手机中显示的名称,
Project Name 是在eclipse中显示的项目名称,(建议不要使用中文,否则在后边打包签名时会有一些不必要的麻烦)
package Name 是在项目中应用程序的包名(一般为公司域名翻转过来,应用的唯一标识)
将项目与svn仓库关联起来?
用客户端的或插件的都可以,在工作中最流行的是用插件,因为比较方便一些,选中项目右键点击-->team-->share Project-->选择svn-->URL输入仓库的地址-->编辑提交注释-->finish;
将项目关联svn仓库后,项目还没有提交到svn仓库中,所以接下来要将项目提交到仓库中,选中项目,右键点击-->提交-->bin、gen自动生成的文件,不提交
#1.2splash界面的作用# **
1 卖弄 logo界面 展示次数 品牌效应
2 项目初始化 数据库copy
3 提醒用户更新版本
4 广告的展示
小步快跑 beta版,一个星期 更新一个版本, 10 11版本:赚钱,抢占市场
#1.3代码包结构划分# **
1.按照代码类型划分 (android 常用的方式)
在做项目时,首先都有一个界面的,界面都是通过Activity来管理的,所以activity就可以管理一些textview、button这些控件,所以说凡是带有activity的操作,全部都存到了.activity包中或者根目录中
在activity中有一些textview、button,这些系统中的textview、button无法满足我们的需求,一般需要我们自己去写一个textView等等自定义控件,像这些自定义控件,一般我们会存到.ui包中,表明是我们自己写的ui控件
此外,界面有了后,界面是用来处理显示ui数据的,所以说android中也是有业务处理的,在javaweb中业务处理,一般都是存放到.service包中,但是android当中有一些特殊的服务组件,所以说业务操作,我们一般都不存放到service中,而是存放到.engine(业务处理)包中
此外,activity中还有一些特殊的处理,比如listview,它会有一些adapter,这个adapter我们也是要单独拿出来放在.adapter包中的
所以,通过业务处理的数据(在.engine包中)会先放到.adapter包中,然后adapter(在.adapter包中)通过activity(在.activity包中或者根目录中)去展示绘制出来,或者业务处理的数据(在.engine)直接给activity,让activity直接展示
有业务处理(在.engine包中),肯定是处理数据的,所以数据我们也是要去获取的,一般在android中获取数据是从两个地方获取,一种是从网络获取,一种是从数据库获取,从网络获取数据一般都存放在.net包中,数据库获取一般都是存放在.db获取是.db.dao中
那么从网络或者数据库获取的数据,传给我们的业务层,业务层将数据处理完后给adapter,adapter在给activity展示出来,或者给activity展示出来,这种流程就是一种mvc模式
有些人会说android中没有mvc模式,其实是有的,只不过android中的mvc模式分的没有javaweb中的那么细,因为有可能业务处理或者数据的显示,都是在activity中做的,都整合到了显示这里去做了
此外,在android中还有一些特殊的组件,比如服务,是存放在.service包中,还有一些广播接收者,是存放在.receiver中包下的,这个是按照代码类型划分的操作
此外还有工具类(存放到.utils/.tools包中),在android开发中,很多情况下工具类中是会出现问题的,所以单独拿出来放在这个包中,比较方便
2.按照业务类型划分
比较适合业务比较独立的项目
传智 项目 www.itcast.cn
教学模块 cn.itcast.teach
招生模块 cn.itcast.student
财务模块 cn.itcast.money
目的:方便的项目的维护和管理
#1.4splash界面搭建# ***
将代码包结构划分之后,接下就该正式处理项目了
首先,先来对splash界面进行处理即activity_splash.xml,
首先第一步需要看下效果图,即看下黑马程序员这张图,拿到效果图后先别急着做,
先来分析一下,该用哪些控件来实现,
首先最上边heima safe 这个文字,用textView就可以实现,
黑马logo可以用imageview来实现,黑马程序员也是一个textview,www.itheima.com网址也是textView来实现,版本号1.0也是textview,
进度条使用progressbar实现,
整体来看,还有一个蓝色的背景,这个就是我们整个splash界面,大多数由textView来实现,
其实不用这么麻烦,因为这里的textView明显是人为手写的,在android中想实现这种效果,是很困难的,所以像这种效果,都是一张图片搞定,即一般将这张图片导进去,splash界面就完成四分之三了,剩下四分之一自己写写就好了
将splash界面(图片luncher_bg.png)拷贝到工程的drawable-hdpi包下,接下来给整体的界面设置一个背景,即在activity_splash.xml中操作,代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/luncher_bg" //此时将luncher_bg.png图片加载上去,即完成四分之三了 >
//图片中没有版本号,进度条,所以需要自己用textView,progressbar画一个
<TextView
android:id="@+id/tv_splash_versionname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="版本号:1.0"
android:layout_centerInParent="true"
//阴影的颜色 给版本号:1.0增加阴影效果
android:shadow.Color="#ffff00"
android:shadowDx="1" //在x轴的偏移量
android:shadowDy="1"
android:shadowRadius="2" //偏移的角度
/>
<ProgressBar
android:id="@+id/progressBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true" />
</RelativeLayout>
注意:一些特殊的效果(比如说textView的阴影)在预览界面是看不到的,即模拟器的预览界面比较弱,一些效果是不支持的
启动模拟器,看到textView的阴影之后,我们接下来还要去掉标题(手机卫士西安2号),这个时候就不能在布局文件中进行操作了,需要到清单文件中去做了,在清单文件的application中有个theme="@style/AppTheme",这个用的是本地styles.xml文件(在工程的values文件夹下的styles.xml),现在需要改成使用安卓系统的样式,即:
android:theme="@android:style/theme.Black.NoTitleBar.Fullscreen"
其中,
NoTitleBar是会将标题栏给隐藏掉
Fullscreen就是会将标题上边的系统通知栏也给隐藏掉,
所以我们一般使用:
android:theme="@android:style/theme.Black.NoTitleBar即可
在运行一下看下效果,标题栏没有了,但是把版本号和进度条的样式也给改变了,
原因:
找到styles.xml文件,原先使用的是:AppTheme,这里还有个parent="AppBaseThem"即继承自AppBaseTheme,就是在styles.xml中上边的AppBaseTheme,它又有个parent="android:Theme.light",即它又继承自Theme.light,这个Theme.light是高亮显示的意思,
所以在看下我们使用在清单文件中使用的theme.Black.NoTitleBar,即将黑色去掉了,只剩下高亮显示了,所以才会将版本号和进度条的样式变成高亮显示,
那怎么去修改呢?
很简单,既然Black.NoTitleBar会将标题给隐藏掉,那么右键点击直接看下源码,它其实也是一个style样式,只不过在里边增加了个item,我们看到他的item是windowNoTitle等于true,这就说它最终能将标题隐藏,完全是这个属性在起作用,即:
<item name="android:windowNoTitle">true</item>
那么我们也可以这么干,直接复制一下,找到我们本地用的样式文件(styles.xml),粘过来即可
现在我们改了,那就在清单文件中不用系统的,还用原来的,即:
android:theme="@style/AppTheme"
在运行看下效果就没有问题了
1.textView的阴影
<!-- layout_centerInParent : 在父控件的中间位置
shadowColor : 阴影的颜色 给版本号:1.0增加阴影效果
shadowDx : 在x轴的偏移量
shadowRadius : 偏移的角度
-->
2.去除标题栏
在清单文件中的application的theme属性中使用本地的样式文件,
在本地的样式文件中添加一个item
<style name="AppTheme" parent="AppBaseTheme">
<!-- 表示隐藏标题栏 -->
<item name="android:windowNoTitle">true</item>
</style>
#1.5获取版本号# ****
splash界面搭建完成后,里面有个版本号,这个版本号现在我们是写死的,即直接在activity_splash.xml的textView中是写死了,现在版本号1.0的作用就是显示我们当前应用程序的版本号的,我们当前应用程序的版本号在清单文件中
即:
package="cn.itcast.mobilesafexian02"
android:versionCode="1" //:应用程序的版本号
android:versionName="1.0" //版本的名称
注意:
清单文件中的package代表的是应用程序的包名,这个包名和我们存放activity的这个目录包名是有区别的,这个目录包名只是用来存放activity的路径,而清单文件中的包名代表的是应用程序在安卓系统中的唯一标识,之后对我们的应用进行操作的时候,都是可以根据这个包名来进行操作的
versionCode代表的是实际的版本号,但是在市面上用的时候,一般用的是versionName
原因是比如versionCode改成2了,versionName不用写成2.0,可以写成1.1,这样在市面给用户看的时候,实际版本是1.1这个版本,这样可以缩减版本号的上线,比如说可能更新10个版本,那versionCode变成12了,如果versionName也写成12的话,那你给用户说,你的这个已经是12个版本了,会把用户给吓死的,所以说一般到12了,我们可能才到2.5(versionCode=2.5),这样用户会比较能接受
在上边版本号是写死的,但它又代表的是我们应用程序的实际版本号
那接下来就要获取下应用程序的实际版本号,然后给填充显示过来,
首先,在splashActivity.java中,创建一个方法,获取一个版本号,最终我们是要把这个版本号返回的,所以需要返回一个string类型,即代码如下:
/**
* 获取应用程序的版本号
*
* @return
*/
public String getVersionName() {
// 1.包的管理者,可以获取应用程序清单文件中的信息
PackageManager packageManager = getPackageManager();
try {
// 2.根据包名获取应用程序相关信息
//参1:packageName : 应用程序的包名 即在清单文件中的packagename="cn.itcast.mobilesafexian02" 清单文件中的包名代表的是应用程序在安卓系统中的唯一标识,对应用进行操作的时候,都是可以根据这个包名来进行操作的
// 参2:flags : 指定信息的标签,指定了标签就会获取相应标签对应的相关信息(即获取原来没有的东西) 写成0:代表的是获取所有的信息
// getPackageName() : 获取应用程序的包名
// PackageManager.GET_ACTIVITIES : 获取跟activity相关的信息
PackageInfo packageInfo = packageManager.getPackageInfo(
getPackageName(), 0);
// 3.获取应用程序版本号名称
String versionName = packageInfo.versionName;
return versionName;
} catch (NameNotFoundException e) {
// 找不到包名的异常
e.printStackTrace();
return null;
}
}
注意:
1.一般什么时候,xxManager都是通过getSystemservice获取的,但是PackageManager的获取有些区别,把鼠标放在PackageManager上,它会提醒你用的是getPackageManager()方式获取的,我们在写的时候会省略掉this,即 this.getPackageManager();
可以省略是因为这个this代表的是SplashActivity 继承的Activiy,而Activity又是继承自context(上下文),所以其实是Context.getPackageManager(); 只不过这里我们可以省略不写
选中Activity,按ctrl+T 可以查看它的继承树,即它继承了哪些东西
2.packageManager.getPackageInfo抛出异常原因:
比如参数1是写具体的包名例如cn.itcast.mobilesafexian02,很容易写错导致找不到包名的异常,所以安卓中考虑到这种情况,给我们提供了一个方法,即getPackageName(),这个方法就可以获取应用程序的包名
最终会返回一个packageInfo,xxInfo,在学java时,我们就知道,代表的就是一个bean类,所以packageInfo就是一个存储信息的对象
接下来就可以将获取来的版本号,填充到textView中
先给textview设置一个id,在开发中id就不能随便写了,因为在开发的时候,一个文件中可能有很多的textView,随便写textView1,textView2的话,不方便后期的维护和管理,所以开发中id的命名一般采用驼峰式命名
id : 驼峰式命名 : 控件的类型_控件所在位置_控件所表示的逻辑内容
例如:android:id="@+id/tv_splash_versionname"
这个id代表的是:它的控件类型为textView,在splash界面上,表示的含义是版本号versionname
接下来初始化一下,在SplashActivity.java中的onCreate方法中,写如下代码:
TextView tv_splash_versionname = (TextView)findViewById(R.id.tv_splash_versionname);
紧接着可以给这个TextView设置一个文本
tv_splash_versionname.setText(“版本号:” + getVersionName());// 设置显示的版本号
#1.6连接服务器# ****
获取应用程序版本号做完之后,就要实现splash界面一个非常重要的功能,即笔记上边提到过的提醒用户更新版本的操作
更新版本步骤:
1.链接服务器(打开tomcat),查看是否有最新版本,如果有的话继续2,没有的话跳转到其他界面
2.弹出对话框,提醒用户更新版本
3.如果点击升级,则要下载最新的版本,点击取消升级,则跳转到其他界面去
4.安装最新的版本
在SplashActivity.java中创建一个方法update,添加如下代码:
/**
* 连接服务器更新版本
*/
private void update() {
//连接服务器,属于联网操作,是耗时操作,4.0以后不允许在主线程中执行耗时操作
new Thread(){
public void run() {
//1.连接服务器
try {
//1.1获取连接地址
URL url = new URL(""http://192.168.1.100:8080/updateinfo.html"");
//1.2获取连接的操作 一般遵循的是http://协议,所以强转成HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//1.3设置超时时间
conn.setConnectTimeout(5000);//连接超时时间
//conn.setReadTimeout(5000);//读取超时时间
//1.4设置请求方式
conn.setRequestMethod("GET");//post
//1.5获取服务器返回的状态码 200 404 500
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
//连接成功
}else{
//连接失败
}
} catch (MalformedURLException e) {
//找不到(有缺陷的)url的异常 同上,url可能写错
e.printStackTrace();
} catch (IOException e) {
//连接异常 可能会连接超时、读取超时,根据服务器返回的状态码判断链接是否成功
e.printStackTrace();
}
};
}.start();
}
注意:
连接超时时间,读取超时时间任取其一即可,一般写连接超时时间,因为读取超时时间,有时候读取的内容比较多的话,5秒之内是读不完的,这个时候它会给你断开链接,就会属于异常操作,所以一般不用读取超时时间
#1.7数据封装形式# ****
连接接服务器的操作实现后,如果连接成功,获取服务返回的数据
首先,服务器返回哪些数据?
1.查看是否有最新版本,首先肯定返回一个新版本的版本号(1.code : 新版本的版本号)
2.下载最新的版本,就要有一个下载最新版本的地址(2.apkurl : 新版本的下载地址)
3.此外还有一个,弹出对话框,提醒用户更新版本时,对话框中会有“本次版本的改进包括:...”等描述信息,这些操作在本地是不可以写死的,也是要从服务器获取的,所以关于一些描述信息,也要获取出来,( 3.des : 描述信息)
链接成功之后,就可以去服务器中获取上边的三个数据,获取数据之前,还需要知道服务器是如何封装数据的?
采用两种形式封装数据:
1.xml
2.json : 最终返回的就是一个json串(字符串)
如何用这两种形式封装数据的?
首先,创建一个文件updateinfo.html,一般后缀用txt或者xml都可以,一般用html方便我们测试,打开编辑如下:
1.使用xml封装数据
第一步:需要有一个文件头
<?xml version="1.0" encoding="utf-8"?>
第二步:需要一个根标签
<xml>
</xml>
第三步:里边需要一个code、apkurl、des等信息
<xml>
<code>2.0</code>
<apkurl>xxxxxxx</apkurl>
<des>新版本上线了,快来下载吧!!!!</des>
</xml>
上边三步就是用xml封装数据的形式,整理如下:
<?xml version="1.0" encoding="utf-8"?>
<xml>
<code>2.0</code>
<apkurl>xxxxxxx</apkurl>
<des>新版本上线了,快来下载吧!!!!</des>
</xml>
用浏览器打开测试一下,乱码了,将浏览器编码格式改一下,即可显示出:
2.0 xxxxxx 新版本上线了,快来下载吧!!!!
2.使用json封装数据,形式如下:
{"code":"2.0","apkurl":"xxxxxxxx","des":"新版本上线了,快来下载吧!!!!"}
一般都用json封装数据,原因很简单,json在封装数据和解析数据的时候,要比xml简单很多
所以市面上只要是没有涉及安全的操作,都是使用json来封装数据,这样比较简单一些
注意:
在使用json封装数据,用的是notepad++编辑时,编码保存的格式是:utf-8无bom格式
用的是editplus编辑时,它有两个选项 utf-8、utf-8+bom
编码保存的格式选择用:utf-8
怎样正确改变编码格式?
1.先将内容全选剪切出来,保存一下
2.然后将格式改为编码需要保存的格式
3.然后再将数据复制回去,再保存一下,即可保存为编码需要保存的格式
使用上边两种方式之一封装完数据后,可以测试一下,即将编辑好的updateinfo.html文件放到tomcat下(相当于放在服务器上了),路径如下:
放到D:\develop\apache-tomcat-7.0.26\webapps\ROOT目录下
将tomcat启动起来,即在D:\develop\apache-tomcat-7.0.26\bin目录下找到startup.bat,双击运行即可
运行测试一下:即打开浏览器,输入http://localhost:8080/updateinfo.html,执行一下,显示:
{"code":"2.0","apkurl":"xxxxxxxx","des":"新版本上线了,快来下载吧!!!!"}
即为向服务器请求后,返回的json串,使用json封装数据后,最终返回的就是上边这种json串的形式,即字符串的形式
将http://localhost:8080/updateinfo.html中的localhost改为具体网址192.168.1.100:8080,添加到下面代码的URL中,代码如下:
/**
* 更新版本
*/
private void update() {
// 连接服务,联网,耗时操作,4.0不允许在主线程中执行耗时操作
new Thread() {
public void run() {
Message message = Message.obtain();
// 在连接之前,获取开始的时间
long startTime = System.currentTimeMillis();
// 1.连接服务器
try {
// 1.1获取连接地址
URL url = new URL(
"http://192.168.1.100:8080/updateinfo.html");
// 1.2获取连接的操作
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();// http://协议
// 1.3设置超时时间
conn.setConnectTimeout(5000);// 连接超时时间
// conn.setReadTimeout(5000);//读取超时时间
// 1.4设置请求方式
conn.setRequestMethod("GET");// post
// 1.5获取服务器返回的状态码 200 404 500
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
// 2.连接成功,获取服务返回的数据 1.code : 新版本的版本号 2.apkurl : 新版本的下载地址
// 3.des : 描述信息
// 2.1.服务器是如何封装数据 xml json : 返回就是一个json串
System.out.println("连接成功.....");
// 2.2获取服务器返回的数据, 流信息 即返回的是一个流信息
InputStream inputStream = conn.getInputStream();
// 2.3.将流信息转化成字符串
String json = StreamUtils.parserStream(inputStream);
// 2.4.解析数据
JSONObject jsonObject = new JSONObject(json);
// 2.5.获取数据
code = jsonObject.getString("code");
apkurl = jsonObject.getString("apkurl");
des = jsonObject.getString("des");
// 3.查看是否有最新版本
// 3.1.判断服务返回code值和我们当前应用程序的版本号是否一致
if (code.equals(getVersionName())) {
// 不升级
message.what = MSG_ENTER_HOME;
} else {
// 升级
// 3.2.弹出对话框
message.what = MSG_UPDATE_DIALOG;
}
} else {
// 连接失败
// System.out.println("连接失败.....");
message.what = MSG_SERVER_ERROR;
}
} catch (MalformedURLException e) {
e.printStackTrace();
message.what = MSG_URL_ERROR;
} catch (IOException e) {
e.printStackTrace();
message.what = MSG_IO_ERROR;
} catch (JSONException e) {
e.printStackTrace();
message.what = MSG_JSON_ERROR;
} finally {// 不管有没有异常,都会执行
// 获取结束的时间
long endTime = System.currentTimeMillis();
// 获取时间差
long dTime = endTime - startTime;
if (dTime < 2000) {
SystemClock.sleep(2000 - dTime);// 保证最终始终睡两秒钟
}
// 1.Thread.sleep有异常SystemClock没有
// 2.Thread.sleep精确不高,SystemClock精确度比较高
// Thread.sleep(2000);
handler.sendMessage(message);
}
};
}.start();
}
因为 连接服务是联网操作,所以还要在清单文件中添加internet权限
运行程序测试一下,如果在控制台输出“连接成功.....”,即说明链接服务器成功,数据已经可以拿到了。
#1.8获取服务器返回的数据# ****
刚才链接成功后,接下来2.2获取服务器返回的数据,流信息
//2.连接成功,获取服务返回的数据 1.code : 新版本的版本号 2.apkurl : 新版本的下载地址 3.des : 描述信息
//2.1.服务器是如何封装数据 xml json : 返回就是一个json串
System.out.println("连接成功.....");
//2.2.获取服务器返回的数据,流信息 即返回的是一个流信息
InputStream inputStream = conn.getInputStream();
//2.3.将流信息转化成字符串
String json = StreamUtils.parserStream(inputStream);
//2.4.解析数据
JSONObject jsonObject = new JSONObject(json);
//2.5.获取数据 参数:name:其实就是json串中的第一个字符串code 返回一个code
code = jsonObject.getString("code");
apkurl = jsonObject.getString("apkurl");
des = jsonObject.getString("des");
System.out.println("code:"+code+" apkurl:"+apkurl+" des:"+des);
运行程序,在控制台输出,说明解析、获取数据成功
注意:
2.2.获取服务器返回的数据,流信息 返回的是一个流信息,
我们最终得到的是一个字符串,所以需要将流信息转化成字符串,像这样的操作,一般会放到工具类当中执行,
如下:
创建工具类StreamUtils.java 工具类写成Utils或Tools都可以
工具类
/**
* 将流信息转化成字符串
* @param in
* @return
* @throws IOException
*/
public class StreamUtils {
//需要将流转化成字符串,所以需要接受一个InputStream流信息,转化成成流信息后,需要返回一个String
public static String parserStream(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();
}
}
注意:
1.工具类中的异常一般选择抛出
2.将流信息转化成字符串,首先需要一个字符流读取流BufferedReader,并且在参数中 new InputStreamReader(in) 即将传过来的流信息转化成字符流,in便是传递过来的流信息,InputStreamReader便是转化流,有读取流便有写入流,写入流读取流都有了以后,就可以进行读写操作了,首先写一个缓冲区,因为是字符流,字符流可以读取一行,所以用字符串去做缓冲区,这个是可以的,一行一行的读取,将读取出的信息放入缓冲区中,并且当缓冲区中不为空时,进行写入操作
3.为什么要用StringWriter这个写入流?
我们最终要得到一个String类型的数据,这就是使用StirngWriter的好处,sw.toString();直接就会得到存放在StirngWriter流里的字符串信息。
到这里,整个将流转化成字符串的操作就做完了,完了之后需要调用,找到splashActivity.java,在这里直接调用如下代码:
//2.3.将流信息转化成字符串
String json = StreamUtils.parserStream(inputStream);
返回的String类型的数据,其实就是json:
{"code":"2.0","apkurl":"xxxxxxxx","des":"新版本上线了,快来下载吧!!!!"}
4.解析数据:
xml封装数据后,解析方式为:
xml.newPullParser(),然后解析各种控件,各种标签,最后解析出来
json没有这么麻烦,
JSONObject jsonObject = new JSONObject(json);
5.json串中的第一个字符串code,这个code在开发中一般叫接口,就是大家会说需求文档,接口文档,这个就是接口文档,接口文档主要就是标明这个code代表什么含义,传什么数据,数据类型是什么,接收储存什么数据,这个code是开发中我们和服务器端去商议的,去和服务器端商议code代表什么含义,或者版本号我们要用什么字段去表示
#1.9查看是否有最新版本,弹出对话框提醒用户更新版本#
获取服务器返回数据的操作也做完了,此时可以查看一下是否有最新版本
splashactivity.java中的更新版本update方法中
1.查看是否有最新版本,在update方法
//3.查看是否有最新版本
//3.1.判断服务返回code值和我们当前应用程序的版本号是否一致
if (code.equals(getVersionName())) {
//不升级
}else{
//升级
//3.2.弹出对话框
message.what = MSG_UPDATE_DIALOG;
}
在finally给handler发送消息
finally{//不管有没有异常,都会执行
handler.sendMessage(message);
}
2.在handler中接受信息做出判断
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_DIALOG:
//弹出对话框
showUpdateDialog();
break;
}
}
};
3.弹出对话框
/**
* 3.3.弹出对话框
*/
protected void showUpdateDialog() {
AlertDialog.Builder builder = new Builder(this);
//设置标题
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();
}
注意:
getVersionName可以获得我们当前应用程序的版本号
#1.10下载最新版本#
/**
* 4.下载最先版本
*/
protected void download() {
HttpUtils httpUtils = new HttpUtils();
//4.1.判断SD卡是否挂载
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//4.2.下载
//url : 新版本的下载地址
//target : 保存下载文件的路径
//callback:回调监听RequestCallBack
httpUtils.download(apkurl, "/mnt/sdcard/mobilesafexian2.0.apk", new RequestCallBack<File>() {
//下载成功的调用
@Override
public void onSuccess(ResponseInfo<File> arg0) {
}
//下载失败的调用
@Override
public void onFailure(HttpException arg0, String arg1) {
}
//4.2.1显示当前的下载进度
//total : 总进度
//current : 当前的进度
//isUploading : 是否支持断点续传
@Override
public void onLoading(long total, long current, boolean isUploading) {
super.onLoading(total, current, isUploading);
//显示控件
tv_spalsh_plan.setVisibility(View.VISIBLE);
//给控件设置显示下载进度
tv_spalsh_plan.setText(current+"/"+total);// 132/520
}
});
}
}
#1.12安装最新版本#
/**
* 5.安装最新的版本
*/
protected void install() {
/**
* <intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />// content://
<data android:scheme="file" />// 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");
//setData和setType是相互冲突的,两个数据是会相互覆盖的
// intent.setType("application/vnd.android.package-archive");
// intent.setData(Uri.fromFile(new File("/mnt/sdcard/mobilesafexian2.0.apk")));
intent.setDataAndType(Uri.fromFile(new File("/mnt/sdcard/mobilesafexian2.0.apk")), "application/vnd.android.package-archive");
//在当前的activity退出的时候,会调用之前activity的OnActivityResult方法
//requestCode : 请求码,表示activity去打开新的activity的时候在新的activity中标示
// a b c 现在a -> c b-> c ,在c中我们是要确定那个a的intent那个是b的intent
//在这里我们用不到 所以0
startActivityForResult(intent, 0);
}
重写OnActivityResult方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
enterHome();
}
#1.13异常的处理#
在开发,尽量把异常细化处理,可以方便我们后期维护管理代码(定位异常)
#1.14两种上下文的区别#
1.getApplicationContext() 返回的是Context
2.this 当前的activity 继承Context
父类中的有方法子类当中一定有,那子类有的方法父类当中不一定有,
在使用getApplicationContext()的时候一定是可以使用activity.this,但是使用activity.this就不一定能使用getApplicationContext()
异常:android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
dialog要想显示出来必须要告诉dialog要显示在那个activity中,要想让dialog显示必须让dialog挂载到一个activity中才可以
凡是跟对话框有关操作的必须使用activity.this
getContext(); 返回的是Context,自定义控件,或者单元测试
#1.15应用签名#
应用要想升级必须满足两个条件
1.包名一致
2.签名一致
微信 com.weixin
流氓程序 com.weixin
所以:签名文件不能丢,签名密码也不能忘,
真的丢了:让原应用下架,重新打包签名生成新的apk,上架
#1.16主界面的搭建#
1.gridview的用法
2.在activity的使用
gv_home_gridview = (GridView) findViewById(R.id.gv_home_gridview);
gv_home_gridview.setAdapter(new MyAdapter());
private class MyAdapter extends BaseAdapter{
int[] imageId = { R.drawable.safe, R.drawable.callmsgsafe, R.drawable.app,
R.drawable.taskmanager, R.drawable.netmanager, R.drawable.trojan,
R.drawable.sysoptimize, R.drawable.atools, R.drawable.settings };
String[] names = { "手机防盗", "通讯卫士", "软件管理", "进程管理", "流量统计", "手机杀毒", "缓存清理",
"高级工具", "设置中心" };
//设置条目的个数
@Override
public int getCount() {
return 9;
}
//设置条目的样式
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//TextView textView = new TextView(getApplicationContext());
//textView.setText("第"+position+"个条目");//position : 代表的时候条目的位置,从0开始 0-8
//将布局文件转化成view对象
View view = View.inflate(getApplicationContext(), R.layout.item_home, null);
ImageView iv_itemhome_imageview = (ImageView) view.findViewById(R.id.iv_itemhome_imageview);//view.findViewById是去item_home布局文件中找,findViewById是去activity_home去找
TextView tv_itemhome_text = (TextView) view.findViewById(R.id.tv_itemhome_text);
//设置图片
iv_itemhome_imageview.setImageResource(imageId[position]);//给imageview设置图片,根据条目的位置去给imagview设置数组相对应的图片
tv_itemhome_text.setText(names[position]);//设置显示的文本
return view;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}