欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

详谈闪屏页相关处理

程序员文章站 2024-02-11 21:53:28
根据功能模块划分(android开发推荐此方法)     - activity   mobilesafe.activty...

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

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

闪屏页面(splash)作用:

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

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

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.mxn.mobilesafe"
 android:versioncode="1" //版本号
 android:versionname="1.0" > //版本名
 <uses-sdk
  android:minsdkversion="16"
  android:targetsdkversion="21" />
//项目所需的权限
 <uses-permission android:name="android.permission.internet" />
 <uses-permission android:name="android.permission.write_external_storage" />
 <uses-permission android:name="android.permission.read_phone_state" />
 <uses-permission android:name="android.permission.receive_boot_completed" />
 <uses-permission android:name="android.permission.read_contacts" />
 <uses-permission android:name="android.permission.send_sms" />
 <uses-permission android:name="android.permission.receive_sms" />
 <uses-permission android:name="android.permission.access_fine_location" />
 <uses-permission android:name="android.permission.access_coarse_location" />
 <uses-permission android:name="android.permission.access_mock_location" />
 <uses-permission android:name="android.permission.vibrate" />
 <uses-permission android:name="android.permission.process_outgoing_calls" />
 <uses-permission android:name="android.permission.kill_background_processes"/>
 <uses-permission android:name="android.permission.get_package_size"/>
 <uses-permission android:name="android.permission.clear_app_cache"/>
 <application
  android:allowbackup="true"
  android:icon="@drawable/ic_launcher"
  android:label="@string/app_name"
  android:theme="@style/apptheme" > //主题
   //activity的注册
  <activity
android:name="com.mxn.mobilesafe.activity.splashactivity"
   android:label="@string/app_name" >
   <intent-filter> //起始的activity
    <action android:name="android.intent.action.main" />
    <category android:name="android.intent.category.launcher" />
   </intent-filter>
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.homeactivity" />
  <activity android:name="com.mxn.mobilesafe.activity.settingactivity" />
  <activity android:name="com.mxn.mobilesafe.activity.lostfindactivity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.setup1activity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.setup2activity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.setup3activity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.setup4activity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.contactactivity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.atoolsactivity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.addressactivity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.callsafeactivity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.appmanageractivity" >
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.taskmanageractivity">   
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.taskmanagersettingactivity">   
  </activity>
  <activity android:name="com.mxn.mobilesafe.activity.antivirusactivity"></activity>
  <activity android:name="com.mxn.mobilesafe.activity.applockactivity"></activity>
  <activity android:name="com.mxn.mobilesafe.activity.cleancacheactivity"></activity>
//广播接收者的 注册
  <receiver android:name=".receiver.bootcompletereceiver" >
   <intent-filter>
    <action android:name="android.intent.action.boot_completed" />
   </intent-filter>
  </receiver>
  <receiver android:name=".receiver.smsreceiver" >
   <intent-filter android:priority="2147483647" >
    <action android:name="android.provider.telephony.sms_received" />
   </intent-filter>
  </receiver>
  <!--
  <receiver android:name=".receiver.outcallreceiver" >静态注册的广播
   <intent-filter>
    <action android:name="android.intent.action.new_outgoing_call" />
   </intent-filter>
  </receiver>
  -->
//服务的注册
  <service android:name="com.mxn.mobilesafe.service.locationservice" >
  </service>
  <service android:name="com.mxn.mobilesafe.service.addressservice" >
  </service>
  <service android:name="com.mxn.mobilesafe.service.killprocessservice"></service>
  <service android:name="com.mxn.mobilesafe.service.watchdogservice"></service>
 </application>
</manifest>

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:paddingbottom="@dimen/activity_vertical_margin" android:paddingleft="@dimen/activity_horizontal_margin"
android:paddingright="@dimen/activity_horizontal_margin"
android:paddingtop="@dimen/activity_vertical_margin"
 tools:context="com.mxn.mobilesafe.splashactivity"
 android:background="@drawable/launcher_bg" 
 android:id="@+id/rl_root">
 <textview
  android:id="@+id/tv_version"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignparentbottom="true"
  android:layout_centerhorizontal="true"
  android:layout_marginbottom="202dp"
  android:textsize="22sp"
  android:textcolor="#000"
  android:shadowcolor="#f00" //对版本号设置阴影
  android:shadowdx="1"
  android:shadowdy="1"
  android:shadowradius="1"
  android:text="版本号:1.0" />
 <progressbar
  android:id="@+id/progressbar1"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_aligntop="@+id/tv_version"
  android:layout_centerhorizontal="true"
  android:layout_margintop="54dp" />
 <textview
  android:id="@+id/tv_progress"
  android:visibility="gone"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignparentbottom="true"
  android:layout_alignparentleft="true"
  android:textcolor="#f00"
  android:textsize="16sp"
  android:text="下载进度" />
</relativelayout>

splashactivity.java

public class splashactivity extends activity {
 protected static final int code_update_dialog;
 protected static final int code_url_error;
 protected static final int code_net_error;
 protected static final int code_json_error;
 protected static final int code_enter_home;
 private textview tvversion;
 private textview tvprogress;// 下载进度展示
 // 服务器返回的信息
 private string mversionname;// 版本名
 private int mversioncode;// 版本号
 private string mdesc;// 版本描述
 private string mdowmloadurl;// 下载地址
 private handler mhandler = new handler() {
  public void handlemessage(android.os.message msg) {
   switch (msg.what) {
   case code_update_dialog:
    showupdatedialog();//显示升级对话框
    break;
   case code_url_error:
    toast.maketext(splashactivity.this, "url错误", toast.length_short).show();
    enterhome();
    break;
   case code_net_error:
    toast.maketext(splashactivity.this, "网络错误", toast.length_short).show();
    enterhome();
    break;
   case code_json_error:
    toast.maketext(splashactivity.this, "json数据解析解析错误", toast.length_short).show();
    enterhome();
    break;
   case code_enter_home:
    enterhome();
    break;
   default:
    break;
   }
  };
 };
 private sharedpreferences sp;
 private relativelayout rlroot;
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_splash);
  tvversion = (textview) findviewbyid(r.id.tv_version);
  tvprogress = (textview) findviewbyid(r.id.tv_progress);// 默认隐藏
  tvversion.settext("版本号:" + getversioncode());//给版本号设置内容,动态获取的值
  rlroot = (relativelayout) findviewbyid(r.id.rl_root);
  //判断是否需要自动更新
  sp = getsharedpreferences("config", mode_private);
  boolean autoupdate = sp.getboolean("auto_update", true);
  copydb("address.db");//拷贝归属地查询数据库
  copydb("antivirus.db");//拷贝病毒库
  //更新病毒库
  updatevirus();
  if(autoupdate){
   checkversion();
  }else{
   mhandler.sendemptymessagedelayed(code_enter_home, 2000);
  }
  //闪屏页渐变动画效果
  alphaanimation anim = new alphaanimation(0.3f, 1f);
  anim.setduration(2000);
  rlroot.startanimation(anim);
 }
 //更新病毒数据库
 private void updatevirus() {
  //联网从服务器获取到最近数据的md5的特征码
  httputils httputils = new httputils();
  string url = "http://172.28.3.112:8080/virus.json";
  httputils.send(httpmethod.get, url, new requestcallback<string>(){
   @override
   public void onfailure(httpexception arg0, string arg1) {
    // todo auto-generated method stub
   }
   @override
   public void onsuccess(responseinfo<string> arg0) {
    // todo auto-generated method stub
    //system.out.println(arg0.result);
//    jsonobject jsonobject = new jsonobject(arg0.result);
//    string md5 = jsonobject.getstring("md5");
//    string desc = jsonobject.getstring("desc");
   }
  });
 }
 // 获取本地版本号
 private int getversioncode() {
  packagemanager packgemanager = getpackagemanager();//拿到包的管理者。。包管理器,获取手机里面每个apk的信息(清单文件信息)
  try {// 获取包的信息。。 getpackagename()当前应用程序的包名 等于 package="com.mxn.mobilesafe"
   packageinfo packageinfo = packgemanager.getpackageinfo(getpackagename(), 0);
   int versioncode = packageinfo.versioncode;
   string versionname = packageinfo.versionname;
   system.out.println("versionname=" + versionname + ";" + "versioncode=" + versioncode);
   return versioncode;
  } catch (namenotfoundexception e) {
   // 没有找到包名时
   e.printstacktrace();
  }
  return -1;
 }
 // 从服务器获取版本信息进行校验
 private void checkversion() {
  final long starttime = system.currenttimemillis();
  new thread() {// 网络访问在分线程异步加载数据
   public void run() {
    message msg = message.obtain();
    httpurlconnection con = null;
    try {// 本机地址:localhost 如果用模拟器加载本机的地址:用10.0.0.2来替换
     url url = new url("http://10.0.2.2:8080/update.json");
     // 打开连接
     con = (httpurlconnection) url.openconnection();
     con.setrequestmethod("get");//设置请求方法
     con.setconnecttimeout(5000);// 设置连接超时,5s
     con.setreadtimeout(5000);// 设置响应超时,链接上了,但服务器迟迟没有响应
     con.connect();// 链接服务器
     int responsecode = con.getresponsecode();//获取响应码
     if (responsecode == 200) {
      // 获取返回值
      inputstream inputstream = con.getinputstream();
      // 流转化为字符串
      string result = streamutils.readformstream(inputstream);//自己定义的streamutils工具类
      system.out.println("网络结果返回:" + result);
       //result是一个json字符串,进行解析
      // 解析json
      jsonobject jo = new jsonobject(result);
      mversionname = jo.getstring("versionname");//拿到服务器端的版本名
      mversioncode = jo.getint("versioncode");//拿到服务器端的版本号
      mdesc = jo.getstring("description");//拿到服务器端的版本描述
      mdowmloadurl = jo.getstring("downloadurl");//拿到服务器端的下载链接
      system.out.println(mdesc);
      system.out.println(mversioncode);
      // 服务器的大于 本地的,判断是否有更新,如果大于 则有更新需要更新,弹出升级对话框
      if (mversioncode > getversioncode()) {
       system.out.println("进行比较,有版本更新");
       msg.what = code_update_dialog;
       // showupdatedialog();//这句是在子线程更新界面,android不能在子线程更新界面,要想在子线程更新界面所以用到handler.
      } else {// 如果没有版本更新
       msg.what = code_enter_home;
      }
     }
    } catch (malformedurlexception e) {// url错误的异常
     msg.what = code_url_error;
     e.printstacktrace();
    } catch (ioexception e) {//网络错误异常
     // 这个是可以携带数据的msg.obj =
     msg.what = code_net_error;// what只是一个标识,用来区分消息!
     e.printstacktrace();
    } catch (jsonexception e) {// json解析失败
     msg.what = code_json_error;
     e.printstacktrace();
    } finally {
     long endtime = system.currenttimemillis();
     long timeused = endtime - starttime;// 访问网络花费的时间
     if (timeused < 2000) {
      try {// 强制休眠2s,保证闪屏页面2s
       thread.sleep(2000 - timeused);
      } catch (interruptedexception e) {
       // todo auto-generated catch block
       e.printstacktrace();
      }
     }
     mhandler.sendmessage(msg);// 消息发送出去,在handlemessage里进行相应的处理
     if (con != null) {
      con.disconnect();
     }
    }
   }
  }.start();
 }
  //升级对话框
 private void showupdatedialog() {
  system.out.println("正在升级对话框");
  // 升级对话框
  alertdialog.builder builder = new alertdialog.builder(this);//context对象
  builder.settitle("最新版本" + mversionname);
  builder.setmessage(mdesc);
  // builder.setcancelable(false);//不让用户取消对话框,用户体验太差
  builder.setpositivebutton("立即更新", new onclicklistener() {
   @override
   public void onclick(dialoginterface dialog, int which) {
    // todo auto-generated method stub
    system.out.println("立即更新");
    // download方法
    download();
   }
  });
  builder.setnegativebutton("以后再说", new onclicklistener() {
   @override
   public void onclick(dialoginterface dialog, int which) {
    enterhome();
   }
  });
  builder.setoncancellistener(new oncancellistener() {
   // 设置取消监听,用户点击返回键时触发
   @override
   public void oncancel(dialoginterface dialog) {
    enterhome();
   }
  });
  builder.show();
 }
 protected void download() {// 下载服务器端的apk文件
  if (environment.getexternalstoragestate().equals(environment.media_mounted)) {
    // 判断是否有sd卡,sd卡挂载的时候才可以
   tvprogress.setvisibility(view.visible);// 显示进度
   string target = environment.getexternalstoragedirectory() + "/update.apk";//把文件下载到哪个路径下,sd卡的根目录
   // xutils框架,使用httputils工具下载文件,下载一个jar包
   httputils utils = new httputils();
   utils.download(mdowmloadurl, target, new requestcallback<file>() {
    @override // 文件下载进度
    public void onloading(long total, long current, boolean isuploading) {
     // todo auto-generated method stub
     super.onloading(total, current, isuploading);
     system.out.println("下载进度:" + current + "/" + total);
     tvprogress.settext("下载进度:" + current * 100 / total + "%");
    }
    @override
    public void onsuccess(responseinfo<file> arg0) {
     // todo auto-generated method stub
     toast.maketext(splashactivity.this, "下载成功", toast.length_short).show();
     // 下载完成之后,跳到系统的安装界面。。intent.action_view 是xml的action 标签
     intent intent = new intent(intent.action_view);//系统的安装界面
     intent.addcategory(intent.category_default);
      intent.setdataandtype(uri.fromfile(arg0.result),
      "application/vnd.android.package-archive");
     // startactivity(intent);
     startactivityforresult(intent, 0);// 如果用户取消安装,会返回结果,回调方法onactivityresult,下文定义
    }
    @override
    public void onfailure(httpexception arg0, string arg1) {
     // todo auto-generated method stub
     toast.maketext(splashactivity.this, "下载失败", toast.length_short).show();
    }
   });
  } else {
   toast.maketext(splashactivity.this, "没有sd卡", toast.length_short).show();
  }
 } 
 @override//用户取消安装,回调此方法
 protected void onactivityresult(int requestcode, int resultcode, intent data) {
  // todo auto-generated method stub
  system.out.println("出现安装界面,用户点击取消时。");
  enterhome();
  super.onactivityresult(requestcode, resultcode, data);
 }
 private void enterhome() {// 进入主界面
  intent intent = new intent(this, homeactivity.class);
  startactivity(intent);
  finish();
 }
 //拷贝数据库,从assets目录下拷贝到data/data/com.mxn.mobilesafe/files目录下
 private void copydb(string dbname){
  //获取文件路径
  file destfile = new file(getfilesdir(),dbname);
  if(destfile.exists()){
   system.out.println("已存在");
  }
  fileoutputstream out = null;
  inputstream in = null;
  try {
   in = getassets().open(dbname);
   out = new fileoutputstream(destfile);
   int len = 0; 
   byte[] buffer = new byte[1024];
   while((len = in.read(buffer))!=-1){
    out.write(buffer,0,len);
   } 
  } catch (ioexception e) {
   // todo auto-generated catch block
   e.printstacktrace();
  }finally{
   try {
    in.close();
    out.close();
   } catch (ioexception e) {
    // todo auto-generated catch block
    e.printstacktrace();
   }
  }
 }
}

streamutils.java

 /*
 * 读取流的工具
 * 把流对象转换成字符串对象
 */
public class streamutils {
 //将输入流读取成string后返回
 public static string readformstream(inputstream in) throws ioexception{
   // 定义字节数组输出流对象 
  bytearrayoutputstream out = new bytearrayoutputstream();
   // 定义读取的长度 
  int len = 0 ;
  // 定义读取的缓冲区
  byte[] buffer = new byte[1024];
   // 按照定义的缓冲区进行循环读取,直到读取完毕为止 
  while((len=in.read(buffer))!=-1){
    // 根据读取的长度写入到字节数组输出流对象中 
   out.write(buffer,0,len);   
  }
  string result = out.tostring();
   // 关闭流 
  in.close();
  out.close();
  return result;
//   // 把读取的字节数组输出流对象转换成字节数组 
//   byte data[] = out.tobytearray(); 
//  // 按照指定的编码进行转换成字符串(此编码要与服务端的编码一致就不会出现乱码问题了,android默认的编码为utf-8) 
//   return new string(data, "utf-8"); 
 }
}

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

<activity android:name=".packageinstalleractivity"
android:configchanges="orientation|keyboardhidden"
android:theme="@style/theme.transparent">
   <intent-filter>
    <action android:name="android.intent.action.view" />
    <category android:name="android.intent.category.default" />
    <data android:scheme="content" />
    <data android:scheme="file" />
    <data android:mimetype="application/vnd.android.package-archive" />
   </intent-filter>
  </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的子类

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!