Android之手机卫士

代码组织结构

  • 根据业务逻辑划分

    • 办公软件

      • 出差 com.itheima.travel

      • 工资 com.itheima.money

      • 会议 com.itheima.meeting

    • 网盘

      • 上传 com.vdisk.upload

      • 下载 com.vdisk.download

      • 分享 com.vdisk.share

  • 根据功能模块划分(Android开发推荐此方法)

    • Activity com.itheima.mobilesafe.activty

    • 后台服务 com.itheima.mobilesafe.service

    • 广播接收者 com.itheima.mobilesafe.receiver

    • 数据库 com.itheima.mobilesafe.db.dao

    • 对象(java bean) com.itheima.mobilesafe.domain/bean

    • 自定义控件 com.itheima.mobilesafe.view

    • 工具类 com.itheima.mobilesafe.utils

    • 业务逻辑 com.itheima.mobilesafe.engine

项目创建

应用名称、项目名称、包名
在这里插入图片描述
版本选择:

  • minimum SDK 要求最低的安装版本, 安装apk前,系统会判断当前版本是否高于(包含)此版本, 是的话才允许安装

  • maxSdkVersion 要求最高的安装版本(一般不用)

  • Target SDK 目标SDK, 一般设置为开发时使用的手机版本, 这样的话,系统在运行我的apk时,就认为我已经在该做了充分的测试, 系统就不会做过多的兼容性判断, 从而提高运行效率

  • Compile With 编译程序时使用的版本

Activity创建

1、闪屏页面(SplashActivity)

  • 展示logo,公司品牌

  • 项目初始化

  • 检测版本更新

  • 校验程序合法性(比如:判断是否有网络,有的话才运行)

1) 根据功能模块创建/修改包名,activity名称
2) 编辑闪屏的布局文件
背景图片
android:background="@drawable/launcher_bg"
显示版本号,居中
android:layout_centerHorizontal="true" android:layout_centerVertical="true"
显示进程图标,版本号正下方,居中
android:layout_below="@+id/tv_Version"

3) 界面内容编程
获取版本号信息
在activity文件中新创建方法getVersionName()–获取版本信息的方法
再在OnCreate()方法中调用该方法

    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        tvVersion = (TextView) findViewById(R.id.tv_Version);    
        tvVersion.setText("版本号:"+getVersionName());
    }
    
    private String getVersionName(){
        PackageManager packageManager = getPackageManager();
        try {
            PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
            //版本名称&版本号
            //android:versionCode="1"
            //android:versionName="1.0"
            int versionCode = packageInfo.versionCode;
            String versionName = packageInfo.versionName;
            return versionName;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "";
    }		

4) 细节界面处理

  • 使手机最上面的主题条不显示
在清单文件中,将主题进行修改 原始为:
<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

修改为:

<application
	android:theme="@android:style/Theme.Black.NoTitleBar" 
  • 字体加阴影
    一般需要给显示字体指定颜色,英文不同版本默认颜色不同;同时还有大小;最终效果见上面的图。
<TextView
        android:id="@+id/tv_Version"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:shadowColor="#f00"
        android:shadowDx="1"    
        android:shadowDy="1"
        android:shadowRadius="1"
        android:textColor="#000"
        android:text="版本号" />
        <!-- 包括阴影颜色、偏移、半径;其中"#f00"代表红色,代表"#000"白色-->

2、网络获取json数据及解析 并弹窗提示更新

流程图:
在这里插入图片描述
将会涉及到的内容:

  • 获取项目自身版本信息 PackageManagerPackageInfo
  • 网络获取数据 URLHttpsURLConnection(需要INTERNET权限)
  • 解析Json JSONObject
  • 子线程使用 Thread
  • Handler处理,& Message
  • 更新对话框弹出 showUpdateDailog

网络获取数据(网络存在延时,需要引用子线程处理,否则导致主线程等待时间长或不确定)得到最新版本信息,与项目自身版本信息比较,判断是否需要更新,更新则弹出对话框给用户(对话框不能放在子线程中处理,又引用Handler来处理,其中消息用Message传递)
从网络获取到的信息需要转换 InputStream->String,此转换按功能模块分类放在工具类Utils中

服务器:Apache.Tomcat

和服务器进行数据交互的大部分都是json格式
{ “name” : “value”,
“name2” : “value2” }

(1) json数据放入服务器
(2) 开启服务器,利用网址连接可访问服务器
将APP的版本信息编辑成Json格式(update.json),存入安装目录的.\webapps\ROOT下面,通过网址http://localhost:8080/update.json可以访问内容

{
	"versionName":"2.0",
	"versionCode":2,
	"description":"NB功能,赶快体验",
	"downloadURL":"http://localhost:8080/update.json"
}
养成良好的编程习惯
- 快捷键:
	* Ctrl + 1	弹出相关提示,可以将变量改成全局编程
	* Ctrl + 2 ,L	自动创建变量类型及名称
- 命名:(首字母适当大写)
	* 布局文件中的控件名称采用形如 **tv_描述**  的格式命名
	* 在activity.java文件中,对应控件采用形如 **tv描述** 的格式命名
	* 全局变量采用形如 **m描述** 的格式命名
1)从服务器获取最新版本信息(网络获取数据,解析Json)

参考blog:Java通过URL 从web服务端获取数据

(1)问题:未将网络获取数据程序段以子线程运行时,报如下错误:

在这里插入图片描述
Android之NetworkOnMainThreadException异常 的理解与处理
主要内容如下:
官宣:从Honeycomb SDK(3.0)开始,google不再允许(禁止)网络请求(HTTP、Socket)等相关操作直接在Main Thread类中,因为直接在UI线程进行网络操作,会阻塞UI、用户体验相当bad!
So 解决方案

  • 和network有关比较耗时的操作放到一个子线程里,然后用Handler消息机制与主线程通信。(本文采用)
  • 使用异步机制如:asynctask,这个举个简单的加载网络图片的例子
  • 直接在main Thread 进行网络操作的方法:在发起Http请求的Activity里面的onCreate函数里面添加相关代码(可参考blog,但也不推荐使用)
	//简单的启动子线程异步加载数据
	new Thread(){
		public void run() {
	     		...
	     	}
	 }.start();
(2)网络获取数据,解析Json,版本对比,子线程处理等编写在同一个方法中

代码如下,结合上下文一起更好理解。

private void checkVersion() {
   //启动子线程异步加载数据
   new Thread(){
       public void run() {
           Message message = Message.obtain();
           HttpURLConnection httpURLConnection = null;
           try {
               //连接服务端
               URL url = new URL("http://10.0.2.2:8080/update.json");
               //把HttpURLConnection与HttpsURLConnection搞错了
               httpURLConnection = (HttpURLConnection) url.openConnection();
               httpURLConnection.setRequestMethod("GET");
               httpURLConnection.setConnectTimeout(5000);
               httpURLConnection.setReadTimeout(5000);
               httpURLConnection.connect();

               int responseCode = httpURLConnection.getResponseCode();
               if (responseCode==200) {
                   //响应成功,获取输入流
                   InputStream inputStream = httpURLConnection.getInputStream();
                   //利用自己编写的工具类将输入流转换成String
                   String result = StreamUtils.readStream(inputStream);

                   //利用Json解析
                   JSONObject jsonObject = new JSONObject(result);
                   mVersionName = jsonObject.getString("versionName");
                   mVersionCode = jsonObject.getInt("versionCode");
                   mDescription = jsonObject.getString("description");
                   mDownloadURL = jsonObject.getString("downloadURL");

                   System.out.println("description:"+mDescription);

                   //判断是否需要更新
                   if (mVersionCode>getVersionCode()) {
                       //需要更新,弹出更新对话框
                       //使用Handler机制,将message.what设置不同属性值,下面else以及各种异常同理
                       message.what = CODE_UPDATE_DIALOG;                              
                   }
                   else {
                       //不需要更新,保持原来页面or进入主页面
                       message.what = CODE_ENTER_HOME;
                   }   
               }                   
           } catch (MalformedURLException e) {
               // URL错误
               message.what = CODE_URL_ERROR;
               e.printStackTrace();
           } catch (IOException e) {
               //连接错误
               message.what = CODE_NET_ERROR;
               e.printStackTrace();
           } catch (JSONException e) {
               // json解析错误
               message.what = CODE_JSON_ERROR;
               e.printStackTrace();
           }finally{
               //将message发送到Handler
               mHandler.sendMessage(message);
               //关闭网络
               if (httpURLConnection != null) {
                   httpURLConnection.disconnect();
               }
           }
       };
   }.start();
}
2)Handler消息机制处理

软件自动补充的mHandler对象的代码如下:
但注意:这是java.util.logging.Handler; 下的Handler,我们需要用的是android.os.Handler;下的Handler

private Handler mHandler = new Handler() {
 
 @Override
 public void publish(LogRecord record) {
  // TODO Auto-generated method stub
  ......
 }
 
 @Override
 public void flush() {
  // TODO Auto-generated method stub
  ......
 }
 
 @Override
 public void close() {
  // TODO Auto-generated method stub
  ......
 }
};

大致编写代码如下:

private Handler mHandler = new Handler() {
    public void handleMessage(android.os.Message message) {
        // TODO Auto-generated method stub
        switch (message.what) {
        case CODE_UPDATE_DIALOG:
            //弹出升级对话框
            break;
        case CODE_ENTER_HOME:
            //进入主页面

            break;
        case CODE_URL_ERROR:
            //弹出吐司:网址错误

            break;
        case CODE_NET_ERROR:
            //弹出吐司:网络出错

            break;
        case CODE_JSON_ERROR:
            //弹出吐司:数据解析错误

            break;
        default:
            break;
        }
    };
};
3)对话框处理
private void showUpdateDailog() {
   AlertDialog.Builder uBuilder = new AlertDialog.Builder(this);
   uBuilder.setTitle("更新版本:"+mVersionName);
   uBuilder.setMessage(mDescription);
   uBuilder.setPositiveButton("立马更新", new OnClickListener() {

       @Override
       public void onClick(DialogInterface dialog, int which) {
           // TODO Auto-generated method stub
           System.out.println("立马更新");	
   		......
       }
   });
   uBuilder.setNegativeButton("以后再说", new OnClickListener() {

       @Override
       public void onClick(DialogInterface dialog, int which) {
           // TODO Auto-generated method stub
           System.out.println("以后再说");
   		......
       }
   });
   uBuilder.show();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值