博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
手机安全卫士——闪屏页相关处理
阅读量:6534 次
发布时间:2019-06-24

本文共 19051 字,大约阅读时间需要 63 分钟。

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

    - Activity   mobilesafe.activty
    - 后台服务   mobilesafe.service
    - 广播接受者 mobilesafe.receiver
    - 数据库 mobilesafe.db.dao
    - 对象(java bean) mobilesafe.domain/bean
    - 自定义控件 mobilesafe.view
    - 工具类 mobilesafe.utils
    - 业务逻辑 mobilesafe.engine

 

 闪屏页面(Splash)作用:

- 展示logo,公司品牌
- 项目初始化,数据库copy
- 检测版本更新
- 校验程序合法性(比如:判断是否有网络,有的话才运行)

 

AndroidMinifest.xml      四大组件都需要在这里配置

1 
2
//版本名 6 7
10 //项目所需的权限11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 27
//主题 //activity的注册32
35
//起始的activity36
38
39
40 41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 //广播接收者的 注册71
72
73
74
75
76
77
78
79
80
81
88 //服务的注册89
90
91
92
93
94
95 96 97

 

activity_splash.xml

 去除标题栏

        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"

 

SplashActivity.java

1 public class SplashActivity extends Activity {  2   3     protected static final int CODE_UPDATE_DIALOG;  4     protected static final int CODE_URL_ERROR;  5     protected static final int CODE_NET_ERROR;  6     protected static final int CODE_JSON_ERROR;  7     protected static final int CODE_ENTER_HOME;  8   9     private TextView tvVersion; 10     private TextView tvProgress;// 下载进度展示 11     // 服务器返回的信息 12     private String mversionName;// 版本名 13     private int mversionCode;// 版本号 14     private String mDesc;// 版本描述 15     private String mdowmloadurl;// 下载地址 16  17     private Handler mHandler = new Handler() { 18         public void handleMessage(android.os.Message msg) { 19             switch (msg.what) { 20             case CODE_UPDATE_DIALOG: 21                 showUpdateDialog();//显示升级对话框 22                 break; 23             case CODE_URL_ERROR: 24                 Toast.makeText(SplashActivity.this, "url错误", Toast.LENGTH_SHORT).show(); 25                 enterHome(); 26                 break; 27             case CODE_NET_ERROR: 28                 Toast.makeText(SplashActivity.this, "网络错误", Toast.LENGTH_SHORT).show(); 29                 enterHome(); 30                 break; 31             case CODE_JSON_ERROR: 32                 Toast.makeText(SplashActivity.this, "json数据解析解析错误", Toast.LENGTH_SHORT).show(); 33                 enterHome(); 34                 break; 35             case CODE_ENTER_HOME: 36                 enterHome(); 37                 break; 38             default: 39                 break; 40             } 41         }; 42     }; 43     private SharedPreferences sp; 44     private RelativeLayout rlRoot; 45  46     @Override 47     protected void onCreate(Bundle savedInstanceState) { 48         super.onCreate(savedInstanceState); 49         setContentView(R.layout.activity_splash); 50          51         tvVersion = (TextView) findViewById(R.id.tv_version); 52         tvProgress = (TextView) findViewById(R.id.tv_progress);// 默认隐藏 53         tvVersion.setText("版本号:" + getVersionCode());//给版本号设置内容,动态获取的值 54          55         rlRoot = (RelativeLayout) findViewById(R.id.rl_root); 56          57          58         //判断是否需要自动更新 59         sp = getSharedPreferences("config", MODE_PRIVATE); 60         boolean autoUpdate = sp.getBoolean("auto_update", true); 61          62         copyDB("address.db");//拷贝归属地查询数据库 63         copyDB("antivirus.db");//拷贝病毒库 64         //更新病毒库 65         updateVirus(); 66          67         if(autoUpdate){ 68             checkVersion(); 69         }else{ 70             mHandler.sendEmptyMessageDelayed(CODE_ENTER_HOME, 2000);//发送一个延时2s的消息 71         } 72          73         //闪屏页渐变动画效果 74         AlphaAnimation anim = new AlphaAnimation(0.3f, 1f);//从哪个度数到哪个度数。。。是0-1的值。从0.3的透明度到完全不透明 75         anim.setDuration(2000);//延时2s 76         rlRoot.startAnimation(anim); 77     } 78  79      80     //更新病毒数据库 81     private void updateVirus() { 82         //联网从服务器获取到最近数据的MD5的特征码 83         HttpUtils httputils = new HttpUtils(); 84         String url = "http://172.28.3.112:8080/virus.json"; 85         httputils.send(HttpMethod.GET, url, new RequestCallBack
(){ 86 87 @Override 88 public void onFailure(HttpException arg0, String arg1) { 89 // TODO Auto-generated method stub 90 91 } 92 93 @Override 94 public void onSuccess(ResponseInfo
arg0) { 95 // TODO Auto-generated method stub 96 //System.out.println(arg0.result); 97 98 // JSONObject jsonobject = new JSONObject(arg0.result); 99 // String md5 = jsonobject.getString("md5");100 // String desc = jsonobject.getString("desc");101 102 }103 104 105 106 });107 108 }109 110 111 112 // 获取本地版本号113 private int getVersionCode() {114 PackageManager packgeManager = getPackageManager();//拿到包的管理者。。包管理器,获取手机里面每个apk的信息(清单文件信息)115 try {
// 获取包的信息。。 getPackageName()当前应用程序的包名 等于 package="com.mxn.mobilesafe" //根据包名获取清单文件中的信息,其实就是返回一个保存有清单文件信息的javabean             //packageName :应用程序的包名             //flags : 指定信息的标签,0:获取基础的信息,比如包名,版本号,要想获取权限等等信息,必须通过标签来指定,才能去获取             //GET_PERMISSIONS : 标签的含义:处理获取基础信息之外,还会额外获取权限的信息             //getPackageName() : 获取当前应用程序的包名116 PackageInfo packageInfo = packgeManager.getPackageInfo(getPackageName(), 0);117 int versionCode = packageInfo.versionCode;118 String versionName = packageInfo.versionName;119 System.out.println("versionname=" + versionName + ";" + "versioncode=" + versionCode);120 return versionCode;121 } catch (NameNotFoundException e) {122 // 没有找到包名时123 e.printStackTrace();124 }125 return -1;126 127 } 128 //连接服务器129 // 从服务器获取版本信息进行校验130 private void checkVersion() {131 final long startTime = System.currentTimeMillis();132 133 new Thread() {
// 网络访问在分线程异步加载数据 1.连接服务器,查看是否有最新版本,  联网操作,耗时操作,4.0以后不允许在主线程中执行的,放到子线程中执行134 public void run() {135 Message msg = Message.obtain();136 HttpURLConnection con = null;137 try {
// 本机地址:localhost 如果用模拟器加载本机的地址:用10.0.0.2来替换 //1.1连接服务器                     //1.1.1设置连接路径                     //spec:连接路径138 URL url = new URL("http://10.0.2.2:8080/update.json");139 1.1.2获取连接操作140 con = (HttpURLConnection) url.openConnection();//http协议,httpClient //1.1.3设置请求方式141 con.setRequestMethod("GET");//设置请求方法 //1.1.4设置超时时间142 con.setConnectTimeout(5000);// 设置连接超时,5S143 con.setReadTimeout(5000);// 设置响应超时,链接上了,但服务器迟迟没有响应144 con.connect();// 链接服务器145 //1.1.5获取服务器返回的状态码,200,404,500146 int responseCode = con.getResponseCode();//获取响应码147 if (responseCode == 200) {
// 解析json148 //1.获取服务器返回的流信息149 InputStream inputStream = con.getInputStream();150 // 2.流转化为字符串151 String result = StreamUtils.readFormStream(inputStream);//自己定义的StreamUtils工具类152 System.out.println("网络结果返回:" + result);153 //3.result是一个json字符串,进行解析154 155 JSONObject jo = new JSONObject(result); //4.获取数据156 mversionName = jo.getString("versionName");//拿到服务器端的版本名157 mversionCode = jo.getInt("versionCode");//拿到服务器端的版本号158 mDesc = jo.getString("description");//拿到服务器端的版本描述159 mdowmloadurl = jo.getString("downloadUrl");//拿到服务器端的下载链接160 161 System.out.println(mDesc);162 System.out.println(mversionCode);163 // 服务器的大于 本地的,判断是否有更新,如果大于 则有更新需要更新,弹出升级对话框164 if (mversionCode > getVersionCode()) {165 System.out.println("进行比较,有版本更新");166 msg.what = CODE_UPDATE_DIALOG;167 // showUpdateDialog();//这句是在子线程更新界面,android不能在子线程更新界面,要想在子线程更新界面所以用到handler.168 } else {
// 如果没有版本更新169 msg.what = CODE_ENTER_HOME;170 }171 }172 } catch (MalformedURLException e) {
// url错误的异常173 msg.what = CODE_URL_ERROR;174 e.printStackTrace();175 } catch (IOException e) {
//网络错误异常176 // 这个是可以携带数据的msg.obj =177 msg.what = CODE_NET_ERROR;// what只是一个标识,用来区分消息!178 e.printStackTrace();179 } catch (JSONException e) {
// json解析失败180 181 msg.what = CODE_JSON_ERROR;182 e.printStackTrace();183 } finally {
//处理对话框延迟显示的问题184 long endTime = System.currentTimeMillis();185 long timeUsed = endTime - startTime;// 访问网络花费的时间186 if (timeUsed < 2000) {187 try {
// 强制休眠2s,保证闪屏页面2S188 Thread.sleep(2000 - timeUsed);189 } catch (InterruptedException e) {190 // TODO Auto-generated catch block191 e.printStackTrace();192 }193 }194 195 mHandler.sendMessage(msg);// 消息发送出去,在handlemessage里进行相应的处理196 if (con != null) {197 con.disconnect();198 }199 200 }201 }202 203 }.start();204 205 }206 //升级对话框207 private void showUpdateDialog() {208 System.out.println("正在升级对话框");209 // 升级对话框210 AlertDialog.Builder builder = new AlertDialog.Builder(this);//context对象211 builder.setTitle("最新版本" + mversionName);212 builder.setMessage(mDesc);213 // builder.setCancelable(false);//不让用户取消对话框,用户体验太差214 builder.setPositiveButton("立即更新", new OnClickListener() {215 @Override216 public void onClick(DialogInterface dialog, int which) {217 // TODO Auto-generated method stub218 System.out.println("立即更新");219 // download方法220 download();221 }222 });223 builder.setNegativeButton("以后再说", new OnClickListener() {224 @Override225 public void onClick(DialogInterface dialog, int which) {226 enterHome();227 }228 });229 builder.setOnCancelListener(new OnCancelListener() {230 // 设置取消监听,用户点击返回键时触发231 @Override232 public void onCancel(DialogInterface dialog) {233 enterHome();234 }235 });236 builder.show();237 } 238 239 protected void download() {
// 下载服务器端的apk文件240 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {241 // 判断是否有sd卡,sd卡挂载的时候才可以242 tvProgress.setVisibility(View.VISIBLE);// 显示进度243 244 String target = Environment.getExternalStorageDirectory() + "/update.apk";//把文件下载到哪个路径下,sd卡的根目录245 // xutils框架,使用HttpUtils工具下载文件,下载一个jar包246 HttpUtils utils = new HttpUtils();247 utils.download(mdowmloadurl, target, new RequestCallBack
() {248 @Override // 文件下载进度249 public void onLoading(long total, long current, boolean isUploading) {250 // TODO Auto-generated method stub251 super.onLoading(total, current, isUploading);252 System.out.println("下载进度:" + current + "/" + total);253 tvProgress.setText("下载进度:" + current * 100 / total + "%");254 }255 256 @Override257 public void onSuccess(ResponseInfo
arg0) {258 // TODO Auto-generated method stub259 Toast.makeText(SplashActivity.this, "下载成功", Toast.LENGTH_SHORT).show();260 // 下载完成之后,跳到系统的安装界面。。Intent.ACTION_VIEW 是xml的action 标签 /*  
                
                
               
//content : 从内容提供者中获取数据  content://                 
// file : 从文件中获取数据                
           
*/ 261 Intent intent = new Intent(Intent.ACTION_VIEW);//系统的安装界面262 intent.addCategory(Intent.CATEGORY_DEFAULT);263 intent.setDataAndType(Uri.fromFile(arg0.result),264 "application/vnd.android.package-archive"); //在当前activity退出的时候,会调用之前的activity的onActivityResult方法          //requestCode : 请求码,用来标示是从哪个activity跳转过来         //ABC  a -> c    b-> c  ,c区分intent是从哪个activity传递过来的,这时候就要用到请求码265 // startActivity(intent);266 startActivityForResult(intent, 0);// 如果用户取消安装,会返回结果,回调方法onActivityResult,下文定义267 }268 269 @Override270 public void onFailure(HttpException arg0, String arg1) {271 // TODO Auto-generated method stub272 Toast.makeText(SplashActivity.this, "下载失败", Toast.LENGTH_SHORT).show();273 }274 });275 } else {276 Toast.makeText(SplashActivity.this, "没有SD卡", Toast.LENGTH_SHORT).show();277 }278 }279 280 @Override//用户取消安装,回调此方法281 protected void onActivityResult(int requestCode, int resultCode, Intent data) {282 // TODO Auto-generated method stub283 System.out.println("出现安装界面,用户点击取消时。");284 enterHome();285 super.onActivityResult(requestCode, resultCode, data);286 }287 288 private void enterHome() {
// 进入主界面289 Intent intent = new Intent(this, HomeActivity.class);290 startActivity(intent);291 finish();292 }293 294 295 296 297 //拷贝数据库,从assets目录下拷贝到data/data/com.mxn.mobilesafe/files目录下298 private void copyDB(String dbName){299 //获取文件路径300 File destFile = new File(getFilesDir(),dbName);301 302 if(destFile.exists()){303 System.out.println("已存在");304 }305 306 307 FileOutputStream out = null;308 InputStream in = null;309 310 try {311 in = getAssets().open(dbName);312 313 out = new FileOutputStream(destFile);314 int len = 0; 315 byte[] buffer = new byte[1024];316 317 while((len = in.read(buffer))!=-1){318 out.write(buffer,0,len);319 }320 321 322 } catch (IOException e) {323 // TODO Auto-generated catch block324 e.printStackTrace();325 }finally{326 try {327 in.close();328 out.close();329 } catch (IOException e) {330 // TODO Auto-generated catch block331 e.printStackTrace();332 }333 334 }335 336 }337 }

 StreamUtils.java

1 /* 2  * 读取流的工具 3  * 把流对象转换成字符串对象 4  */ 5 public class StreamUtils { 6     //将输入流读取成String后返回 7     public static String readFormStream(InputStream in) throws IOException{ 8          // 定义字节数组输出流对象  9         ByteArrayOutputStream out = new ByteArrayOutputStream();10          // 定义读取的长度 11         int len = 0 ;12         // 定义读取的缓冲区13         byte[] buffer = new byte[1024];14          // 按照定义的缓冲区进行循环读取,直到读取完毕为止  15         while((len=in.read(buffer))!=-1){16              // 根据读取的长度写入到字节数组输出流对象中  17             out.write(buffer,0,len);            18         }19         String result = out.toString();20           // 关闭流  21         in.close();22         out.close();23         return result;24 //         // 把读取的字节数组输出流对象转换成字节数组  25 //          byte data[] = out.toByteArray();  26 //        // 按照指定的编码进行转换成字符串(此编码要与服务端的编码一致就不会出现乱码问题了,android默认的编码为UTF-8)  27 //          return new String(data, "UTF-8");  28         29     }30 31 }

 系统安装界面的activity的配置:

 

我们服务器用的是tomcat,里面放置  新版本的apk和update.json:

 

将代码打包为apk文件:

 

 

 

涉及的知识点:

PackageManager  包管理器,获取手机里面每个apk的信息(清单文件信息)

版本更新流程:

                  

网络请求

>  * URL
>  * HttpUrlConntetion

JSON解析

> * JSONObject  专门用来解析json
> * JSONArray

对话框弹出

> AlertDialog
> AlertDialog.Builder

 

子线程更新UI

> * Handler + message
> * runOnUiThread(runnable)

 

页面之间的跳转Intent

 

 GitHub 一个开源的网站,下载xUtils框架,将下载的jar包导入工程。

 

AlertDialog.Builder(this)

子类拥有父类的所有方法, 而且可以有更多自己的方法。父类无法有子类的方法

Activity(token), Context(没有token)
平时,要获取context对象的话, 优先选择Activity, 避免bug出现, 尽量不用getApplicationContext()
activity是context的子类

 

转载于:https://www.cnblogs.com/mengxiao/p/6364731.html

你可能感兴趣的文章
第十一课 xshell实现linux与windows互文件、用户与密码的配置文件、用户和用户组的管理...
查看>>
jQuery EasyUI使用教程之使用虚拟滚动视图显示海量数据
查看>>
jQuery EasyUI使用教程之添加节点到树形菜单
查看>>
BCGControlBar中文教程之Ribbon Backstage视图(三)
查看>>
《Linux学习并不难》文件/目录管理(7):rmdir命令删除空目录
查看>>
8天学通MongoDB——第四天 索引操作
查看>>
简单登录系统
查看>>
51CTO学院四周年# 每天进步一点点”;
查看>>
maven中对jsp预编译方法
查看>>
abr-summary 和asbr-summary命令中的not-advertise参数
查看>>
数据库隔离级别
查看>>
小型企业局域网免费上网行为管理方案
查看>>
【研究任务】热迁移方式——pre-copy、post-copy和x-multifd
查看>>
Anaconda3启动ipython的几种方式
查看>>
Windows下安装Scrapy方法及常见安装问题总结——Scrapy安装教程
查看>>
十六、lvm、磁盘故障小案例
查看>>
技本功丨请带上纸笔刷着看:解读MySQL执行计划的type列和extra列
查看>>
nginx基础
查看>>
MySQL主从复制虽好,能完美解决数据库单点问题吗?
查看>>
工作态度的重要性
查看>>