Android--底部导航栏的动态替换方案

摘要:
使用RadioGroup+RadioButton实现底部的选项卡。任务完成后,IntentService将自动停止。我们不需要手动结束它。如果多次启动IntentService,每个耗时的操作都将以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并按顺序执行。执行后,它将以串行方式自动结束。FilePathUtil.getHuaShengHomeTabImgCurrentDirectory:FilePathUtil。getHuaShengHomeTabImgNextDirectory);日志。d、 }4.事实上,最重要的是如何创建和获取我们的文件资源。最重要的是在两种资源状态之间切换。通常,我们使用drawbable来写˂?

1、通常来说,一般情况下,我们的app的BottomTab会有集中实现方式。

  1. 自定义view,然后自己写逻辑去实现互斥。
    • 自由度最高,因为啥都是自己写的。
  2. 使用RadioGroup+RadioButton去实现底部的Tab。
    • 自由度比极高,如果想实现搞复杂度的话可以重写RadioButton。
  3. 使用google design包里面的 TabLayout去实现。
    • 可上、可下、可以滑动
    • 偷懒的话可以根据已有api来设置一些资源,也可以setCustomView()
  4. 使用google design包里面的BottomNavigationView去实现。
    • 使用menu设置资源
    • 有默认的动画效果。

2、今天来讲一下基于TabLayout来实现的根据后台下发实现动态替换底部导航资源图片的方法。

  • 因为动态替换肯定意味着下载资源,所以先讲一下IntentService

    • IntentService也是一个service,只不过google帮我们在里面封装并维护了一个HandlerThread,里面的操作都是异步的。
    • 当任务执行完后,IntentService 会自动停止,不需要我们去手动结束。
    • 如果启动 IntentService 多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,使用串行的方式,执行完自动结束。
  • 这里面最重要的方法onHandlerIntent(Intent intent)
    • @Override
          protected voidonHandleIntent(Intent intent) {
              if (intent != null) {
                  final String action =intent.getAction();
                  if(ACTION_FOO.equals(action)) {
                      //在这里面处理耗时任务,当所有的耗时任务都结束以后,IntentService会自动的finish掉,不需要开发者关心。
      }
              }
          }
3、选择IntentService的原因(下面的这几个操作都是耗时操作,所以我们干脆都封装到这service里面,我们只需要在合适的时机去启动这个Service就ok了)

    • 需要下载资源压缩包
      • 因为是动态替换,所以必然涉及到预下载,所以数据格式要先定好(下面是数据格式)。
      • {
                "currentInfo":{//当前样式
                    "id":"111",
                    "imageZipUrl":"http://oc8ql3urp.bkt.clouddn.com/currentInfo.zip",
                    "tabNamesList":[
                            "首页1","产品1","发现1","我的1"
                    ],
                    "tabColorNormal":"B0C4DE",
                    "tabColorHighlight":"F7B62D",
                    "startTime":"1517846400000",
                    "deadLineTime":"1518710400000"
                },
                "nextInfo":{//下一次要展示的样式
                    "id":"111",
                    "imageZipUrl":"http://oc8ql3urp.bkt.clouddn.com/nextInfo.zip",
                    "tabNamesList":[
                            "首页2","产品2","发现2","我的2"
                    ],
                    "tabColorNormal":"B0C4DE",
                    "tabColorHighlight":"FE6246",
                    "startTime":"1417846400000",
                    "deadLineTime":"1518710400000"
                }
            }
    • 需要存放资源压缩包
      • 下载和存放文件的代码(我这里使用的是Retrofit进行下载的)
      • //下载文件
                    Response<ResponseBody> zipFile = ServiceGenerator.createService(HomeService.class)
                            .downloadFileRetrofit(getFileDownLoadUrl(homeTabImageInfoBean, type))
                            .execute();
                    //得到文件流
                    ResponseBody zipBody =zipFile.body();
                    LogUtils.d("HomeTabImageDownLoadInt", "下载完成---");
                    //创建一个文件
                    File zipDirectory = newFile(FilePathUtil.getHuaShengHomeTabZipDirectory(getApplicationContext())
                            +createZipFileName(homeTabImageInfoBean, type));
                    //如果文件不存在,则创建文件夹
                    if (!zipDirectory.exists()) {
                        zipDirectory.createNewFile();
                    }
                    //保存文件
                    FileUtils.writeFile2Disk(zipBody, zipDirectory);
    • 需要解压资源压缩方
      • 解压的话就是使用java里面的那几个类进行解压的操作
      • //解压文件 并删除文件
                    if(ZipUtils.unzipFile(zipDirectory.getAbsolutePath(),
                            CURRENT.equals(type) ?FilePathUtil.getHuaShengHomeTabImgCurrentDirectory(getApplicationContext())
                                    : FilePathUtil.getHuaShengHomeTabImgNextDirectory(getApplicationContext()))) {
                        //保存文件解压地址
        saveFileDirPath(homeTabImageInfoBean, type,
                                CURRENT.equals(type) ?FilePathUtil.getHuaShengHomeTabImgCurrentDirectory(getApplicationContext())
                                        : FilePathUtil.getHuaShengHomeTabImgNextDirectory(getApplicationContext()));
                        LogUtils.d("HomeTabImageDownLoadInt", "解压完成---");
                    }

    4、其实最关键的就是如何创建并获取我们的文件资源

      • 最重要的就是资源的两种状态切换(选中 or 不选中),通常我们都是使用drawable来写的
      • <?xml version="1.0" encoding="utf-8"?>
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
            <item android:drawable="@mipmap/home_tab_financing_selected"android:state_selected="true" />
            <item android:drawable="@mipmap/home_tab_financing_normal" />
        </selector>
      • 现在我们要根据下载下来的图片(存放在sdcard中)去动态创建drawable,这样我们便能里面系统控件的互斥特性,下面的三个方法代码很重要
      •     //构建Drawable选择器
            privateStateListDrawable createDrawableSelector(Drawable checked, Drawable unchecked) {
                StateListDrawable stateList = newStateListDrawable();
                int state_selected =android.R.attr.state_selected;
                stateList.addState(new int[]{state_selected}, checked);
                stateList.addState(new int[]{-state_selected}, unchecked);
                returnstateList;
            }
            //构建颜色选择器
            private ColorStateList createColorSelector(int checkedColor, intuncheckedColor) {
                return newColorStateList(
                        new int[][]{new int[]{android.R.attr.state_selected},
                                new int[]{-android.R.attr.state_selected}},
                        new int[]{checkedColor, uncheckedColor});
            }
            //将文件转换成Drawable
            //pathName就是图片存放的绝对路径
            privateDrawable getDrawableByFile(String pathName) {
                returnDrawable.createFromPath(pathName);
            }

    5、如何给TabLayout设置上资源我觉得就不需要我来说了吧

      • 取出TabLayout的所有的Tab,遍历,然后根据特定条件去设置相应的drawable

    好了,这样就可以实现底部Tab动态替换了,最后奉上一个解压的工具类

    1 importcom.blankj.utilcode.util.CloseUtils;
    2 importcom.blankj.utilcode.util.StringUtils;
    3 
    4 importjava.io.BufferedInputStream;
    5 importjava.io.BufferedOutputStream;
    6 importjava.io.File;
    7 importjava.io.FileInputStream;
    8 importjava.io.FileOutputStream;
    9 importjava.io.IOException;
    10 importjava.io.InputStream;
    11 importjava.io.OutputStream;
    12 importjava.util.ArrayList;
    13 importjava.util.Collection;
    14 importjava.util.Enumeration;
    15 importjava.util.List;
    16 importjava.util.zip.ZipEntry;
    17 importjava.util.zip.ZipFile;
    18 importjava.util.zip.ZipOutputStream;
    19 
    20 /**
    21 * <pre>
    22 *     author: Blankj
    23 *     blog  : http://blankj.com
    24 *     time  : 2016/08/27
    25 *     desc  : 压缩相关工具类
    26 * </pre>
    27  */
    28 public final classZipUtils {
    29 
    30     private static final int KB = 1024;
    31 
    32     privateZipUtils() {
    33         throw new UnsupportedOperationException("u can't instantiate me...");
    34 }
    35 
    36     /**
    37 * 批量压缩文件
    38 *
    39 * @paramresFiles    待压缩文件集合
    40 * @paramzipFilePath 压缩文件路径
    41 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    42 * @throwsIOException IO错误时抛出
    43      */
    44     public static boolean zipFiles(Collection<File>resFiles, String zipFilePath)
    45             throwsIOException {
    46         return zipFiles(resFiles, zipFilePath, null);
    47 }
    48 
    49     /**
    50 * 批量压缩文件
    51 *
    52 * @paramresFiles    待压缩文件集合
    53 * @paramzipFilePath 压缩文件路径
    54 * @paramcomment     压缩文件的注释
    55 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    56 * @throwsIOException IO错误时抛出
    57      */
    58     public static boolean zipFiles(Collection<File>resFiles, String zipFilePath, String comment)
    59             throwsIOException {
    60         returnzipFiles(resFiles, FileUtils.getFileByPath(zipFilePath), comment);
    61 }
    62 
    63     /**
    64 * 批量压缩文件
    65 *
    66 * @paramresFiles 待压缩文件集合
    67 * @paramzipFile  压缩文件
    68 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    69 * @throwsIOException IO错误时抛出
    70      */
    71     public static boolean zipFiles(Collection<File>resFiles, File zipFile)
    72             throwsIOException {
    73         return zipFiles(resFiles, zipFile, null);
    74 }
    75 
    76     /**
    77 * 批量压缩文件
    78 *
    79 * @paramresFiles 待压缩文件集合
    80 * @paramzipFile  压缩文件
    81 * @paramcomment  压缩文件的注释
    82 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    83 * @throwsIOException IO错误时抛出
    84      */
    85     public static boolean zipFiles(Collection<File>resFiles, File zipFile, String comment)
    86             throwsIOException {
    87         if (resFiles == null || zipFile == null) return false;
    88         ZipOutputStream zos = null;
    89         try{
    90             zos = new ZipOutputStream(newFileOutputStream(zipFile));
    91             for(File resFile : resFiles) {
    92                 if (!zipFile(resFile, "", zos, comment)) return false;
    93 }
    94             return true;
    95         } finally{
    96             if (zos != null) {
    97 zos.finish();
    98 CloseUtils.closeIO(zos);
    99 }
    100 }
    101 }
    102 
    103     /**
    104 * 压缩文件
    105 *
    106 * @paramresFilePath 待压缩文件路径
    107 * @paramzipFilePath 压缩文件路径
    108 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    109 * @throwsIOException IO错误时抛出
    110      */
    111     public static booleanzipFile(String resFilePath, String zipFilePath)
    112             throwsIOException {
    113         return zipFile(resFilePath, zipFilePath, null);
    114 }
    115 
    116     /**
    117 * 压缩文件
    118 *
    119 * @paramresFilePath 待压缩文件路径
    120 * @paramzipFilePath 压缩文件路径
    121 * @paramcomment     压缩文件的注释
    122 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    123 * @throwsIOException IO错误时抛出
    124      */
    125     public static booleanzipFile(String resFilePath, String zipFilePath, String comment)
    126             throwsIOException {
    127         returnzipFile(FileUtils.getFileByPath(resFilePath), FileUtils.getFileByPath(zipFilePath), comment);
    128 }
    129 
    130     /**
    131 * 压缩文件
    132 *
    133 * @paramresFile 待压缩文件
    134 * @paramzipFile 压缩文件
    135 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    136 * @throwsIOException IO错误时抛出
    137      */
    138     public static booleanzipFile(File resFile, File zipFile)
    139             throwsIOException {
    140         return zipFile(resFile, zipFile, null);
    141 }
    142 
    143     /**
    144 * 压缩文件
    145 *
    146 * @paramresFile 待压缩文件
    147 * @paramzipFile 压缩文件
    148 * @paramcomment 压缩文件的注释
    149 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    150 * @throwsIOException IO错误时抛出
    151      */
    152     public static booleanzipFile(File resFile, File zipFile, String comment)
    153             throwsIOException {
    154         if (resFile == null || zipFile == null) return false;
    155         ZipOutputStream zos = null;
    156         try{
    157             zos = new ZipOutputStream(newFileOutputStream(zipFile));
    158             return zipFile(resFile, "", zos, comment);
    159         } finally{
    160             if (zos != null) {
    161 CloseUtils.closeIO(zos);
    162 }
    163 }
    164 }
    165 
    166     /**
    167 * 压缩文件
    168 *
    169 * @paramresFile  待压缩文件
    170 * @paramrootPath 相对于压缩文件的路径
    171 * @paramzos      压缩文件输出流
    172 * @paramcomment  压缩文件的注释
    173 * @return{@codetrue}: 压缩成功<br>{@codefalse}: 压缩失败
    174 * @throwsIOException IO错误时抛出
    175      */
    176     private static booleanzipFile(File resFile, String rootPath, ZipOutputStream zos, String comment)
    177             throwsIOException {
    178         rootPath = rootPath + (isSpace(rootPath) ? "" : File.separator) +resFile.getName();
    179         if(resFile.isDirectory()) {
    180             File[] fileList =resFile.listFiles();
    181             //如果是空文件夹那么创建它,我把'/'换为File.separator测试就不成功,eggPain
    182             if (fileList == null || fileList.length <= 0) {
    183                 ZipEntry entry = new ZipEntry(rootPath + '/');
    184                 if (!StringUtils.isEmpty(comment)) entry.setComment(comment);
    185 zos.putNextEntry(entry);
    186 zos.closeEntry();
    187             } else{
    188                 for(File file : fileList) {
    189                     //如果递归返回false则返回false
    190                     if (!zipFile(file, rootPath, zos, comment)) return false;
    191 }
    192 }
    193         } else{
    194             InputStream is = null;
    195             try{
    196                 is = new BufferedInputStream(newFileInputStream(resFile));
    197                 ZipEntry entry = newZipEntry(rootPath);
    198                 if (!StringUtils.isEmpty(comment)) entry.setComment(comment);
    199 zos.putNextEntry(entry);
    200                 byte buffer[] = new byte[KB];
    201                 intlen;
    202                 while ((len = is.read(buffer, 0, KB)) != -1) {
    203                     zos.write(buffer, 0, len);
    204 }
    205 zos.closeEntry();
    206             } finally{
    207 CloseUtils.closeIO(is);
    208 }
    209 }
    210         return true;
    211 }
    212 
    213     /**
    214 * 批量解压文件
    215 *
    216 * @paramzipFiles    压缩文件集合
    217 * @paramdestDirPath 目标目录路径
    218 * @return{@codetrue}: 解压成功<br>{@codefalse}: 解压失败
    219 * @throwsIOException IO错误时抛出
    220      */
    221     public static boolean unzipFiles(Collection<File>zipFiles, String destDirPath)
    222             throwsIOException {
    223         returnunzipFiles(zipFiles, FileUtils.getFileByPath(destDirPath));
    224 }
    225 
    226     /**
    227 * 批量解压文件
    228 *
    229 * @paramzipFiles 压缩文件集合
    230 * @paramdestDir  目标目录
    231 * @return{@codetrue}: 解压成功<br>{@codefalse}: 解压失败
    232 * @throwsIOException IO错误时抛出
    233      */
    234     public static boolean unzipFiles(Collection<File>zipFiles, File destDir)
    235             throwsIOException {
    236         if (zipFiles == null || destDir == null) return false;
    237         for(File zipFile : zipFiles) {
    238             if (!unzipFile(zipFile, destDir)) return false;
    239 }
    240         return true;
    241 }
    242 
    243     /**
    244 * 解压文件
    245 *
    246 * @paramzipFilePath 待解压文件路径
    247 * @paramdestDirPath 目标目录路径
    248 * @return{@codetrue}: 解压成功<br>{@codefalse}: 解压失败
    249 * @throwsIOException IO错误时抛出
    250      */
    251     public static boolean unzipFile(String zipFilePath, String destDirPath) throwsIOException {
    252         //判断是否存在这个路径,没有的话就创建这个路径
    253         File tempDir = newFile(destDirPath);
    254         if (!tempDir.exists()) {
    255 tempDir.mkdirs();
    256 }
    257         returnunzipFile(FileUtils.getFileByPath(zipFilePath), FileUtils.getFileByPath(destDirPath));
    258 }
    259 
    260     /**
    261 * 解压文件
    262 *
    263 * @paramzipFile 待解压文件
    264 * @paramdestDir 目标目录
    265 * @return{@codetrue}: 解压成功<br>{@codefalse}: 解压失败
    266 * @throwsIOException IO错误时抛出
    267      */
    268     public static booleanunzipFile(File zipFile, File destDir)
    269             throwsIOException {
    270         return unzipFileByKeyword(zipFile, destDir, null) != null;
    271 }
    272 
    273     /**
    274 * 解压带有关键字的文件
    275 *
    276 * @paramzipFilePath 待解压文件路径
    277 * @paramdestDirPath 目标目录路径
    278 * @paramkeyword     关键字
    279 * @return返回带有关键字的文件链表
    280 * @throwsIOException IO错误时抛出
    281      */
    282     public static List<File>unzipFileByKeyword(String zipFilePath, String destDirPath, String keyword)
    283             throwsIOException {
    284         returnunzipFileByKeyword(FileUtils.getFileByPath(zipFilePath),
    285 FileUtils.getFileByPath(destDirPath), keyword);
    286 }
    287 
    288     /**
    289 * 解压带有关键字的文件
    290 *
    291 * @paramzipFile 待解压文件
    292 * @paramdestDir 目标目录
    293 * @paramkeyword 关键字
    294 * @return返回带有关键字的文件链表
    295 * @throwsIOException IO错误时抛出
    296      */
    297     public static List<File>unzipFileByKeyword(File zipFile, File destDir, String keyword)
    298             throwsIOException {
    299         if (zipFile == null || destDir == null) return null;
    300         List<File> files = new ArrayList<>();
    301         ZipFile zf = newZipFile(zipFile);
    302         Enumeration<?> entries =zf.entries();
    303         while(entries.hasMoreElements()) {
    304             ZipEntry entry =((ZipEntry) entries.nextElement());
    305             String entryName =entry.getName();
    306             if (StringUtils.isEmpty(keyword) ||FileUtils.getFileName(entryName).toLowerCase().contains(keyword.toLowerCase())) {
    307                 String filePath = destDir + File.separator +entryName;
    308                 File file = newFile(filePath);
    309 files.add(file);
    310                 if(entry.isDirectory()) {
    311                     if (!FileUtils.createOrExistsDir(file)) return null;
    312                 } else{
    313                     if (!FileUtils.createOrExistsFile(file)) return null;
    314                     InputStream in = null;
    315                     OutputStream out = null;
    316                     try{
    317                         in = newBufferedInputStream(zf.getInputStream(entry));
    318                         out = new BufferedOutputStream(newFileOutputStream(file));
    319                         byte buffer[] = new byte[KB];
    320                         intlen;
    321                         while ((len = in.read(buffer)) != -1) {
    322                             out.write(buffer, 0, len);
    323 }
    324                     } finally{
    325 CloseUtils.closeIO(in, out);
    326 }
    327 }
    328 }
    329 }
    330         returnfiles;
    331 }
    332 
    333     /**
    334 * 获取压缩文件中的文件路径链表
    335 *
    336 * @paramzipFilePath 压缩文件路径
    337 * @return压缩文件中的文件路径链表
    338 * @throwsIOException IO错误时抛出
    339      */
    340     public static List<String>getFilesPath(String zipFilePath)
    341             throwsIOException {
    342         returngetFilesPath(FileUtils.getFileByPath(zipFilePath));
    343 }
    344 
    345     /**
    346 * 获取压缩文件中的文件路径链表
    347 *
    348 * @paramzipFile 压缩文件
    349 * @return压缩文件中的文件路径链表
    350 * @throwsIOException IO错误时抛出
    351      */
    352     public static List<String>getFilesPath(File zipFile)
    353             throwsIOException {
    354         if (zipFile == null) return null;
    355         List<String> paths = new ArrayList<>();
    356         Enumeration<?> entries =getEntries(zipFile);
    357         while(entries.hasMoreElements()) {
    358 paths.add(((ZipEntry) entries.nextElement()).getName());
    359 }
    360         returnpaths;
    361 }
    362 
    363     /**
    364 * 获取压缩文件中的注释链表
    365 *
    366 * @paramzipFilePath 压缩文件路径
    367 * @return压缩文件中的注释链表
    368 * @throwsIOException IO错误时抛出
    369      */
    370     public static List<String>getComments(String zipFilePath)
    371             throwsIOException {
    372         returngetComments(FileUtils.getFileByPath(zipFilePath));
    373 }
    374 
    375     /**
    376 * 获取压缩文件中的注释链表
    377 *
    378 * @paramzipFile 压缩文件
    379 * @return压缩文件中的注释链表
    380 * @throwsIOException IO错误时抛出
    381      */
    382     public static List<String>getComments(File zipFile)
    383             throwsIOException {
    384         if (zipFile == null) return null;
    385         List<String> comments = new ArrayList<>();
    386         Enumeration<?> entries =getEntries(zipFile);
    387         while(entries.hasMoreElements()) {
    388             ZipEntry entry =((ZipEntry) entries.nextElement());
    389 comments.add(entry.getComment());
    390 }
    391         returncomments;
    392 }
    393 
    394     /**
    395 * 获取压缩文件中的文件对象
    396 *
    397 * @paramzipFilePath 压缩文件路径
    398 * @return压缩文件中的文件对象
    399 * @throwsIOException IO错误时抛出
    400      */
    401     public static Enumeration<?>getEntries(String zipFilePath)
    402             throwsIOException {
    403         returngetEntries(FileUtils.getFileByPath(zipFilePath));
    404 }
    405 
    406     /**
    407 * 获取压缩文件中的文件对象
    408 *
    409 * @paramzipFile 压缩文件
    410 * @return压缩文件中的文件对象
    411 * @throwsIOException IO错误时抛出
    412      */
    413     public static Enumeration<?>getEntries(File zipFile)
    414             throwsIOException {
    415         if (zipFile == null) return null;
    416         return newZipFile(zipFile).entries();
    417 }
    418 
    419     private static booleanisSpace(String s) {
    420         if (s == null) return true;
    421         for (int i = 0, len = s.length(); i < len; ++i) {
    422             if (!Character.isWhitespace(s.charAt(i))) {
    423                 return false;
    424 }
    425 }
    426         return true;
    427 }
    428 }
    工具类

    免责声明:文章转载自《Android--底部导航栏的动态替换方案》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

    上篇cron表达式学习使用element-ui中的loading时发现close()报错,俗称 配置了loading中的optios就无法close()的一部分解答下篇

    宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

    相关文章

    JAVA发送HTTP请求方式

    1. HttpURLConnection 使用JDK原生提供的net,无需其他jar包; HttpURLConnection是URLConnection的子类,提供更多的方法,使用更方便。 package httpURLConnection; import java.io.BufferedReader; import java.io.InputStrea...

    Springboot + Mybatis 多数据源配置

    1、src/main/resources/application.properties 中配置好多个数据源   spring.datasource.initialize=false  #接口请求端口号、路径  server.port=9090  servcer.context-path=/  #mybatis配置  #mybatis.config-loca...

    spring boot 支持返回 xml

    实现技术方式对比 JAXB(Java Architecture for XML Binding) 是一个业界的标准,可以实现java类和xml的互转 jdk中包括JAXB JAXB vsjackson-dataformat-xml spring boot中默认使用jackson返回json,jackson-dataformat-xml 中的 XmlMapp...

    uniapp app-plus pages.json

    app-plus Object 设置编译到 App 平台的特定样式,配置项参考下方 app-plus App 参考地址 https://uniapp.dcloud.io/collocation/pages app-plus配置编译到 App 平台时的特定样式,部分常用配置 H5 平台也支持。以下仅列出常用,更多配置项参考 WebviewStyles。 ti...

    C#实现短链接生成服务

    项目中有一处需求,需要把长网址缩为短网址,把结果通过短信、微信等渠道推送给客户。刚开始直接使用网上现成的开放服务,然后在某个周末突然手痒想自己动手实现一个别具特色的长网址(文本)缩短服务。 由于以前做过socket服务,对数据包的封装排列还有些印象,因此,短网址服务我第一反应是先设计数据的存储格式,我这里没有采用数据库,而是使用2个文件来实现: Url...

    接口测试——流量录制回放

    接口自动化回归技术是我们经常谈到的一种质量保证手段,如今在测试行业针对它的应用已经比较广泛。对于一个轻量级的系统,当我们想针对它完成一个接口自动化回归工具的时候,我们通常都是通过手动梳理的方法将目前系统应用的对外接口列出来然后,然后查阅接口文档,录入测试用例,最终完成断言,看似是一个完美的解决方案。 但是如果面对磅礴复杂的系统,我们还是采用这样的手段,怕是...