Android 项目开发必备-Utils类的建立与使用

timg (1).jpg

我们在进行项目开发的时候可能会遇到一些获取屏幕宽度,dp px的相互转换等问题,我们当然不能每用一次就复制粘贴一次。这时候就需要一个利器-工具类。
这个工具类包含了我们一些公用的方法,只需要一句话我们就可以拿到想要的结果,既精简了我们的代码又省下了我们宝贵的时间。同时,一个好的软件工程师,万能的工具类便是他的护身法宝。
和上一篇文章一样 我只拿出几个特殊比较难理解的方法去讲解其余的我会贴在git上,如果有不懂得可以和我交流,我会把讲解贴到这篇文章里。
Github:https://github.com/EspressoToast/BaseTest
以下工具类包括:请求权限帮助类,校验帮助类,通用工具类,拼接文字,图片帮助类,MD5加密帮助类,String格式化帮助类,软键盘帮助类等

校验

大多数的app都会带有登陆注册功能,所以手机号和密码的校验是我们无法绕过的。
手机号码校验
我们先去建立一个枚举类对应几种校验的结果.

    public enum PhoneNumberCheck{
        /**校验通过**/
        CHECK_SUCCESS,
        /**号码为空**/
        NUMBER_IS_NULL,
        /**长度不足11位**/
        NUMBER_TOO_SHORT,
        /**电话号码首位不为1**/
        NUMBER_START_NOT_ONE,
        /**电话号码不全是数字组成**/
        NUMBER_IS_NOT_NUMBER
    }

接下来是方法.

    /**
     * 手机号码有效性校验
     */
    public static PhoneNumberCheck checkPhoneNumber(String phoneNumber){
        if(null == phoneNumber || phoneNumber.length() == 0){//号码为空
            return PhoneNumberCheck.NUMBER_IS_NULL;
        }else if(phoneNumber.length() != 11){//长度不足11位
            return PhoneNumberCheck.NUMBER_TOO_SHORT;
        }else if(!phoneNumber.startsWith("1")){//首位不为1
            return PhoneNumberCheck.NUMBER_START_NOT_ONE;
        }else if(!checkIsNumber(phoneNumber)){//不是全数字组成
            return PhoneNumberCheck.NUMBER_IS_NOT_NUMBER;
        }
        return PhoneNumberCheck.CHECK_SUCCESS;
    }

然后我们就可以通过去调用这个方法根据他的返回值来输出我们的结果了.
密码校验
只提供一个正则便可以达到我们想要的效果。

    //密码正则 必须包含字母,数字,特殊字符三种中的两种组合,并且长度在6-16位
    private static final String PWD_REGEX = "(?!^\\d+$)(?!^[a-zA-Z]+$)(?!^[~!@#$%^&*()_+-=]+$).{6,16}";

     /**
     * 密码正则校验
     *
     */
    public static boolean checkPwdRegex(String str){
        return null != str && str.matches(PWD_REGEX);
    }

log工具类

一个合格的项目缺少不了日志管理工具,有了日志管理工具我们可以更加方便的去调试程序。

public class Logger {
    /**
     * Wrapper API for logging
     */
    protected final static String TAG = "YourProjectName"; // /< LOG TAG
    protected final static int LOG_OUTPUT_MAX_LENGTH = 300;


    public static void output(String msg) {
        wrapperMsg(msg);
    }

    /**
     * Wrapper the message
     *
     * @param msg : The message to wrapper
     */
    protected static void wrapperMsg(String msg) {
        if (null == msg || !isDebugMode()) {
            return;
        }

        while (msg.length() > LOG_OUTPUT_MAX_LENGTH) {
            final String tempMsg = msg.substring(0, LOG_OUTPUT_MAX_LENGTH);
            msg = msg.substring(LOG_OUTPUT_MAX_LENGTH, msg.length());
            Log.d(TAG, tempMsg);
        }

        StackTraceElement elem = new Throwable().fillInStackTrace()
                .getStackTrace()[2];
        Log.d(TAG, msg + "(" + elem.getFileName() + " : " + elem.getLineNumber() + ")");
    }

    public static void i(String tag, String msg) {
        Log.i(tag, msg);
    }

    public static void e(String tag, String msg) {
        Log.e(tag, msg);
    }

    public static void d(String tag, String msg) {
        Log.e(tag, msg);
    }

    private static boolean isDebugMode() {

        return false;
    }
}

加密

项目里的密码或者其他数据为了保证安全就需要我们把它们加密。以下是常用的几种加密工具类:

/**
 *
 * MD5加密工具类
 */
public class MD5 {

    // MD5加密
    private static final char HEX_DIGITS[] = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public static String md5(String s) {
        try {
            // Create MD5 Hash
            MessageDigest digest = MessageDigest
                    .getInstance("MD5");
            digest.update(s.getBytes());
            byte[] messageDigest = digest.digest();
            return toHexString(messageDigest).toLowerCase();
        } catch (NoSuchAlgorithmException e) {
            Logger.output("MD5 Exception:" + e.getMessage());
            return "";
        }
    }


    private static String toHexString(byte[] b) { // String to byte
        StringBuilder sb = new StringBuilder(b.length * 2);
        for (byte aB : b) {
            sb.append(HEX_DIGITS[(aB & 0xf0) >>> 4]);
            sb.append(HEX_DIGITS[aB & 0x0f]);
        }
        return sb.toString();
    }

}
public class Base64 {
    /** prevents anyone from instantiating this class */
    private Base64() {
    }

    /**
     * This character array provides the alphabet map from RFC1521.
     */
    private final static char ALPHABET[] = {
        //       0    1    2    3    4    5    6    7
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',  // 0
                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',  // 1
                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',  // 2
                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',  // 3
                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',  // 4
                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',  // 5
                'w', 'x', 'y', 'z', '0', '1', '2', '3',  // 6
                '4', '5', '6', '7', '8', '9', '+', '/'  // 7
        };

    /**
     * Decodes a 7 bit Base64 character into its binary value.
     */
    private static int valueDecoding[] = new int[128];

    /**
     * initializes the value decoding array from the
     * character map
     */
    static {
        for (int i = 0; i < valueDecoding.length; i++) {
            valueDecoding[i] = -1;
        }

        for (int i = 0; i < ALPHABET.length; i++) {
            valueDecoding[ALPHABET[i]] = i;
        }
    }

    /**
     * 
     * @return base64 string 
     */
    public static String encodeFile(String filePath) throws IOException{
        if(null != filePath){
            File file = new File(filePath);
            if(file.exists()){
                FileInputStream inputFile = new FileInputStream(file);
                byte[] buffer = new byte[(int)file.length()];
                inputFile.read(buffer);
                inputFile.close();
                return encode(buffer, 0, buffer.length);
            }
        }
        return null;
    }
    
    /**
     * Converts a byte array into a Base64 encoded string.
     * @param data bytes to encode
     * @param offset which byte to start at
     * @param length how many bytes to encode; padding will be added if needed
     * @return base64 encoding of data; 4 chars for every 3 bytes
     */
    public static String encode(byte[] data, int offset, int length) {
        int i;
        int encodedLen;
        char[] encoded;

        // 4 chars for 3 bytes, run input up to a multiple of 3
        encodedLen = (length + 2) / 3 * 4;
        encoded = new char [encodedLen];

        for (i = 0, encodedLen = 0; encodedLen < encoded.length;
             i += 3, encodedLen += 4) {
            encodeQuantum(data, offset + i, length - i, encoded, encodedLen);
        }

        return new String(encoded);
    }

    /**
     * Encodes 1, 2, or 3 bytes of data as 4 Base64 chars.
     *
     * @param in buffer of bytes to encode
     * @param inOffset where the first byte to encode is
     * @param len how many bytes to encode
     * @param out buffer to put the output in
     * @param outOffset where in the output buffer to put the chars
     */
    private static void encodeQuantum(byte in[], int inOffset, int len,
                                      char out[], int outOffset) {
        byte a = 0, b = 0, c = 0;

        a = in[inOffset];
        out[outOffset] = ALPHABET[(a >>> 2) & 0x3F];

        if (len > 2) {
            b = in[inOffset + 1];
            c = in[inOffset + 2];
            out[outOffset + 1] = ALPHABET[((a << 4) & 0x30) +
                                         ((b >>> 4) & 0xf)];
            out[outOffset + 2] = ALPHABET[((b << 2) & 0x3c) +
                                          ((c >>> 6) & 0x3)];
            out[outOffset + 3] = ALPHABET[c & 0x3F];
        } else if (len > 1) {
            b = in[inOffset + 1];
            out[outOffset + 1] = ALPHABET[((a << 4) & 0x30) +
                                         ((b >>> 4) & 0xf)];
            out[outOffset + 2] =  ALPHABET[((b << 2) & 0x3c) +
                                          ((c >>> 6) & 0x3)];
            out[outOffset + 3] = '=';
        } else {
            out[outOffset + 1] = ALPHABET[((a << 4) & 0x30) +
                                         ((b >>> 4) & 0xf)];
            out[outOffset + 2] = '=';
            out[outOffset + 3] = '=';
        }
    }

    /**
     * Converts a Base64 encoded string to a byte array.
     * @param encoded Base64 encoded data
     * @return decode binary data; 3 bytes for every 4 chars - minus padding
     * @exception IOException is thrown, if an I/O error occurs reading the data
     */
    public static byte[] decode(String encoded)
            throws IOException {
        return decode(encoded, 0, encoded.length());
    }

    /**
     * Converts an embedded Base64 encoded string to a byte array.
     * @param encoded a String with Base64 data embedded in it
     * @param offset which char of the String to start at
     * @param length how many chars to decode; must be a multiple of 4
     * @return decode binary data; 3 bytes for every 4 chars - minus padding
     * @exception IOException is thrown, if an I/O error occurs reading the data
     */
    public static byte[] decode(String encoded, int offset, int length)
            throws IOException {
        int i;
        int decodedLen;
        byte[] decoded;

        // the input must be a multiple of 4
        if (length % 4 != 0) {
            throw new IOException(
                "Base64 string length is not multiple of 4");
        }

        // 4 chars for 3 bytes, but there may have been pad bytes
        decodedLen = length / 4 * 3;
        if (encoded.charAt(offset + length - 1) == '=') {
            decodedLen--;
            if (encoded.charAt(offset + length - 2) == '=') {
                decodedLen--;
            }
        }

        decoded = new byte [decodedLen];
        for (i = 0, decodedLen = 0; i < length; i += 4, decodedLen += 3) {
            decodeQuantum(encoded.charAt(offset + i),
                          encoded.charAt(offset + i + 1),
                          encoded.charAt(offset + i + 2),
                          encoded.charAt(offset + i + 3),
                          decoded, decodedLen);
        }

        return decoded;
    }

    /**
     * Decode 4 Base64 chars as 1, 2, or 3 bytes of data.
     *
     * @param in1 first char of quantum to decode
     * @param in2 second char of quantum to decode
     * @param in3 third char of quantum to decode
     * @param in4 forth char of quantum to decode
     * @param out buffer to put the output in
     * @param outOffset where in the output buffer to put the bytes
     */
    private static void decodeQuantum(char in1, char in2, char in3, char in4,
                                byte[] out, int outOffset)
        throws IOException {
        int a = 0, b = 0, c = 0, d = 0;
        int pad = 0;

        a = valueDecoding[in1 & 127];
        b = valueDecoding[in2 & 127];

        if (in4 == '=') {
            pad++;
            if (in3 == '=') {
                pad++;
            } else {
                c = valueDecoding[in3 & 127];
            }
        } else {
            c = valueDecoding[in3 & 127];
            d = valueDecoding[in4 & 127];
        }

        if (a < 0 || b < 0 || c < 0 || d < 0) {
            throw new IOException("Invalid character in Base64 string");
        }

        // the first byte is the 6 bits of a and 2 bits of b
        out[outOffset] = (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3));

        if (pad < 2) {
            // the second byte is 4 bits of b and 4 bits of c
            out[outOffset + 1] = (byte)(((b << 4) & 0xf0) | ((c >>> 2) & 0xf));

            if (pad < 1) {
                // the third byte is 2 bits of c and 4 bits of d
                out[outOffset + 2] =
                    (byte)(((c << 6) & 0xc0) | (d  & 0x3f));
            }
        }
    }

}

下载apk并自动更新
为什么要单独提出这个方法来呢?因为正好前两天遇到了一个坑导致这个方法出问题了,于是查了查资料发现是android7.0系统适配的问题。


   /**
     * 安装APK
     *  我是以前的安装apk方法
     * @return
     */
    public static void installApk(Context context, File file) {
        Intent intent = new Intent();
        //执行动作
        intent.setAction(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        //执行的数据类型

        intent.setDataAndType(FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + BuildConfig.APPLICATION_ID + ".provider", file)
                , "application/vnd.android.package-archive"); //此处Android应为android,否则造成安装不了
        context.startActivity(intent);
    }

  /**
     * 安装APK
     * 我是现在的apk安装方法
     * @return
     */
    public static void installApk(Context context, File file) {
        Intent intent = new Intent();
        //执行动作
        intent.setAction(Intent.ACTION_VIEW);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", file);
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        if (context.getPackageManager().queryIntentActivities(intent, 0).size() > 0) {
            context.startActivity(intent);
        }
    }

如果按照我以前的逻辑在6.0以上会报这个异常:

[android.os.FileUriExposedException:

原因是如果你的sdk是24或者更高的话你必须使用fileprovider来访问特定的文件。 具体操作方案点击这里
https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed

下一篇文章预告--Android 项目开发必备-建立属于你的.gradle文件

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容