MobileSafeNotes Day01

#手机卫士西安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;
			}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值