• 手机安全卫士——闪屏页相关处理


    根据功能模块划分(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 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.mxn.mobilesafe"
     4     android:versionCode="1"  //版本号
     5     android:versionName="1.0" > //版本名
     6 
     7     <uses-sdk
     8         android:minSdkVersion="16"
     9         android:targetSdkVersion="21" />
    10 //项目所需的权限
    11     <uses-permission android:name="android.permission.INTERNET" />
    12     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    13     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    14     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    15     <uses-permission android:name="android.permission.READ_CONTACTS" />
    16     <uses-permission android:name="android.permission.SEND_SMS" />
    17     <uses-permission android:name="android.permission.RECEIVE_SMS" />
    18     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    19     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    20     <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    21     <uses-permission android:name="android.permission.VIBRATE" />
    22     <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    23     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
    24     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
    25     <uses-permission android:name="android.permission.CLEAR_APP_CACHE"/>
    26 
    27     <application
    28         android:allowBackup="true"
    29         android:icon="@drawable/ic_launcher"
    30         android:label="@string/app_name"
    31         android:theme="@style/AppTheme" >  //主题

    //activity的注册
    32 <activity 33 android:name="com.mxn.mobilesafe.activity.SplashActivity" 34 android:label="@string/app_name" > 35 <intent-filter> //起始的activity 36 <action android:name="android.intent.action.MAIN" /> 38 <category android:name="android.intent.category.LAUNCHER" /> 39 </intent-filter> 40 </activity> 41 <activity android:name="com.mxn.mobilesafe.activity.HomeActivity" /> 42 <activity android:name="com.mxn.mobilesafe.activity.SettingActivity" /> 43 <activity android:name="com.mxn.mobilesafe.activity.LostFindActivity" > 44 </activity> 45 <activity android:name="com.mxn.mobilesafe.activity.Setup1Activity" > 46 </activity> 47 <activity android:name="com.mxn.mobilesafe.activity.Setup2Activity" > 48 </activity> 49 <activity android:name="com.mxn.mobilesafe.activity.Setup3Activity" > 50 </activity> 51 <activity android:name="com.mxn.mobilesafe.activity.Setup4Activity" > 52 </activity> 53 <activity android:name="com.mxn.mobilesafe.activity.ContactActivity" > 54 </activity> 55 <activity android:name="com.mxn.mobilesafe.activity.AtoolsActivity" > 56 </activity> 57 <activity android:name="com.mxn.mobilesafe.activity.AddressActivity" > 58 </activity> 59 <activity android:name="com.mxn.mobilesafe.activity.CallSafeActivity" > 60 </activity> 61 <activity android:name="com.mxn.mobilesafe.activity.AppManagerActivity" > 62 </activity> 63 <activity android:name="com.mxn.mobilesafe.activity.TaskManagerActivity"> 64 </activity> 65 <activity android:name="com.mxn.mobilesafe.activity.TaskManagerSettingActivity"> 66 </activity> 67 <activity android:name="com.mxn.mobilesafe.activity.AntivirusActivity"></activity> 68 <activity android:name="com.mxn.mobilesafe.activity.AppLockActivity"></activity> 69 <activity android:name="com.mxn.mobilesafe.activity.CleanCacheActivity"></activity> 70 //广播接收者的 注册 71 <receiver android:name=".receiver.BootCompleteReceiver" > 72 <intent-filter> 73 <action android:name="android.intent.action.BOOT_COMPLETED" /> 74 </intent-filter> 75 </receiver> 76 <receiver android:name=".receiver.SmsReceiver" > 77 <intent-filter android:priority="2147483647" > 78 <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 79 </intent-filter> 80 </receiver> 81 <!-- 82 <receiver android:name=".receiver.OutCallReceiver" >静态注册的广播 83 <intent-filter> 84 <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> 85 </intent-filter> 86 </receiver> 87 --> 88 //服务的注册 89 <service android:name="com.mxn.mobilesafe.service.LocationService" > 90 </service> 91 <service android:name="com.mxn.mobilesafe.service.AddressService" > 92 </service> 93 <service android:name="com.mxn.mobilesafe.service.KillProcessService"></service> 94 <service android:name="com.mxn.mobilesafe.service.WatchDogService"></service>

    95 </application> 96 97 </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"  //关于x轴偏移量
            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"//给控件id命名采用驼峰式命名:   控件类型_控件的所在位置_控件表示的逻辑内容
            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>

     去除标题栏
            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<String>(){
     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<String> 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);// 设置连接超时,5S 143 con.setReadTimeout(5000);// 设置响应超时,链接上了,但服务器迟迟没有响应 144 con.connect();// 链接服务器 145 //1.1.5获取服务器返回的状态码,200,404,500 146 int responseCode = con.getResponseCode();//获取响应码 147 if (responseCode == 200) {
    // 解析json
    148 //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,保证闪屏页面2S 188 Thread.sleep(2000 - timeUsed); 189 } catch (InterruptedException e) { 190 // TODO Auto-generated catch block 191 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 @Override 216 public void onClick(DialogInterface dialog, int which) { 217 // TODO Auto-generated method stub 218 System.out.println("立即更新"); 219 // download方法 220 download(); 221 } 222 }); 223 builder.setNegativeButton("以后再说", new OnClickListener() { 224 @Override 225 public void onClick(DialogInterface dialog, int which) { 226 enterHome(); 227 } 228 }); 229 builder.setOnCancelListener(new OnCancelListener() { 230 // 设置取消监听,用户点击返回键时触发 231 @Override 232 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<File>() { 248 @Override // 文件下载进度 249 public void onLoading(long total, long current, boolean isUploading) { 250 // TODO Auto-generated method stub 251 super.onLoading(total, current, isUploading); 252 System.out.println("下载进度:" + current + "/" + total); 253 tvProgress.setText("下载进度:" + current * 100 / total + "%"); 254 } 255 256 @Override 257 public void onSuccess(ResponseInfo<File> arg0) { 258 // TODO Auto-generated method stub 259 Toast.makeText(SplashActivity.this, "下载成功", Toast.LENGTH_SHORT).show(); 260 // 下载完成之后,跳到系统的安装界面。。Intent.ACTION_VIEW 是xml的action 标签
    /*  <intent-filter>
                     <action android:name="android.intent.action.VIEW" />
                     <category android:name="android.intent.category.DEFAULT" />
                    <data android:scheme="content" /> //content : 从内容提供者中获取数据  content://
                     <data android:scheme="file" /> // file : 从文件中获取数据
                    <data android:mimeType="application/vnd.android.package-archive" />
                </intent-filter>*/
    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 @Override 270 public void onFailure(HttpException arg0, String arg1) { 271 // TODO Auto-generated method stub 272 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 stub 283 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 block 324 e.printStackTrace(); 325 }finally{ 326 try { 327 in.close(); 328 out.close(); 329 } catch (IOException e) { 330 // TODO Auto-generated catch block 331 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的配置:

    <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的子类

  • 相关阅读:
    Jmeter的两种录制脚本的方式
    【.NET】设置EntityFramework中decimal类型数据精度 [转]
    vscode格式化vue不换行
    mysql5.7 noinstall 安装 【转载】
    配置STP、RSTP以及负载均衡
    配置3层交换机VLAN间通信
    配置单臂路由
    配置DTP
    配置trunk
    配置VLAN
  • 原文地址:https://www.cnblogs.com/mengxiao/p/6364731.html
Copyright © 2020-2023  润新知