详谈闪屏页相关处理

发布时间 - 2026-01-10 22:51:48    点击率:

根据功能模块划分(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的子类

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


# 闪屏  # Android实现闪屏欢迎界面  # Android中闪屏实现方法小结(普通闪屏、倒计时闪屏、倒计时+动画闪屏)  # Android切换至SurfaceView时闪屏(黑屏闪一下)以及黑屏移动问题的解决方法  # Android实现闪屏及注册和登录界面之间的切换效果  # android实现Splash闪屏效果示例  # C#双缓冲实现方法(可防止闪屏)  # Android 实现闪屏页和右上角的倒计时跳转实例代码  # EasyUI闪屏EasyUI页面加载提示(原理+代码+效果图)  # Android闪屏效果实现方法  # 背景  # 文字渐变(无闪屏)  # 对话框  # 子类  # 判断是否  # 转换成  # 病毒库  # 弹出  # 管理器  # 本机  # 回调  # 自己的  # 的是  # 是一个  # 加载  # 是在  # 在这里  # 目录下  # 上了  # 下载地址  # 所需  # 能在 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何快速打造个性化非模板自助建站?  jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】  香港服务器建站指南:外贸独立站搭建与跨境电商配置流程  javascript读取文本节点方法小结  详解Oracle修改字段类型方法总结  googleplay官方入口在哪里_Google Play官方商店快速入口指南  Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】  Laravel定时任务怎么设置_Laravel Crontab调度器配置  如何登录建站主机?访问步骤全解析  佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】  如何快速搭建高效香港服务器网站?  Android Socket接口实现即时通讯实例代码  Internet Explorer官网直接进入 IE浏览器在线体验版网址  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  Linux系统运维自动化项目教程_Ansible批量管理实战  在centOS 7安装mysql 5.7的详细教程  海南网站制作公司有哪些,海口网是哪家的?  Laravel如何实现URL美化Slug功能_Laravel使用eloquent-sluggable生成别名【方法】  装修招标网站设计制作流程,装修招标流程?  iOS发送验证码倒计时应用  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法  昵图网官网入口 昵图网素材平台官方入口  国美网站制作流程,国美电器蒸汽鍋怎么用官方网站?  Laravel API资源类怎么用_Laravel API Resource数据转换  如何在VPS电脑上快速搭建网站?  php结合redis实现高并发下的抢购、秒杀功能的实例  使用C语言编写圣诞表白程序  标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  php json中文编码为null的解决办法  如何快速搭建个人网站并优化SEO?  Python文本处理实践_日志清洗解析【指导】  Android仿QQ列表左滑删除操作  JavaScript Ajax实现异步通信  Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程  Laravel如何处理文件下载请求?(Response示例)  如何在万网自助建站中设置域名及备案?  EditPlus中的正则表达式实战(5)  PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  Laravel怎么生成URL_Laravel路由命名与URL生成函数详解  Java解压缩zip - 解压缩多个文件或文件夹实例  详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点  JavaScript常见的五种数组去重的方式  javascript基本数据类型及类型检测常用方法小结  Laravel Admin后台管理框架推荐_Laravel快速开发后台工具  Swift中循环语句中的转移语句 break 和 continue  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  如何在阿里云虚拟服务器快速搭建网站?  如何在景安云服务器上绑定域名并配置虚拟主机?