字符串基本运用 与 位运算

    应用层,更多的是对数据进行一些简单的处理,然后更新到UI上。如果对性能要求不高的情况时,只要不是太复杂的,动动脑子,基本都没问题。如果对性能要求较高时,就要动一番脑筋了。比如项目中有个简单的小功能。   
    场景介绍: 新闻类资讯,列表中每条新闻都会有一些标题,简介和标签,比如 暖文 广告 原创 专题 热门 置顶 等等标签,每条目中都要显示相对应的标签。
    刚开始每个标签只有三个,每个都用一个boolean 属性值代表。如果为true,则在ListView 的 item 上显示对应的标签,后来标签逐渐增多,有十多个,并且这些标签可以共存,客户端bean对应的属性也由3个增加到十多个,按照这个速度,如果有100个标签,岂不是要写100个属性,所以为了方便客户端和服务端,决定改变做法,用一个属性字段来标识所有属性值。
    如果每个item只显示一个标签或者不显示标签,我们可以定义数据,从0开始,0表示不显示,1对应 暖文,2对应 广告,3对应 原创 等等,依次类推,但是 我们这里标签是可以共存的,意思是说可能同时要显示 暖文  原创  热门 置顶 四个标签,这是都是不确定的,怎么办?回归到上面说的用一个字段表示所有属性,titleDisplay :"11010010" 。定义了一个常量,从右往左,每一位数字代表一个标签,1表示有该标签,0表示没有该标签,从右到左,依次为 暖文 广告 原创 专题 热门 置顶 等等。以后如果增加新的标签,往数据的左边补数据。所以,我们需要把该属性数据进行解析,获取1对应的位值,放到一个集合中,同时要做兼容处理,万一客户端返回数据由8位变为10位,老版客户端解析不能出错。拿到数据后,再根据数据值拿对应的标签。
    刚开始做的时候,用一般的方法。


    public static final String TEST_STR = "1111010010"; //  测试数据
    public static final int TITLE_DISPLAY_LENGTH = 8; //置顶热门等标签属性的字符串最小长度
    public static final int TITLE_DISPLAY_LENGTH2 = TITLE_DISPLAY_LENGTH - 1; //辅助值,标签属性长度小1
    public static final int TITLE_DISPLAY_FLAG = 49; //置顶热门等标签值为1,转换为字符值为49


    private static List hotIndex = new ArrayList<>();




    private void signTitleDisplay(String titleDisplay) {
        if (!TextUtils.isEmpty(titleDisplay) && titleDisplay.length() >= TITLE_DISPLAY_LENGTH) {
            String newTitleDisplay = titleDisplay.substring(titleDisplay.length() - TITLE_DISPLAY_LENGTH);
            char[] stringArr = newTitleDisplay.toCharArray();
            for (int count = stringArr.length - 1; count >= 0; count--) {
                if (TITLE_DISPLAY_FLAG == stringArr[count]) {
                    hotIndex.add(TITLE_DISPLAY_LENGTH2 - count); // a
                }
            }
        }
    }
// 调用方法
signTitleDisplay(TEST_STR);

    把 titleDisplay :"11010010" 转换为字符数组,遍历每一个字符的值,比较值是否是 49, 因为字符表中字符1对应的值为49。为了兼容,防止出错,需要对titleDisplay 进行 非空判断 和 长度判断,如果长度大于8位,需要截取后八位,因为前面的数据是新加的。 堆数据判断截取后,转换为数组,然后遍历,如果等于1,则把索引添加到集合中。注意 a 步骤,对索引进行了一个小运算,因为字符串变为数组时遍历时,是从左往右的,而当初定需求时,是从右往左的,所以需要取倒,用数组索引的最后一位,减去当前的索引,添加的集合中。例子中集合中的值为 1 4 6 7。可以去拿对应的标签的。


    private void signTitleDisplay2(String titleDisplay) {
        char[] stringArr = titleDisplay.toCharArray();
        reverseArr(stringArr);
        for (int count = stringArr.length - 1; count >= 0; count--) {
            if ((TITLE_DISPLAY_FLAG == stringArr[count]) {
                hotIndex.add(count);
            }
        }
    }

    private void reverseArr(char[] arr) {
        if(arr != null){
            int start = 0, end = arr.length - 1;
            char t;
            while(start < end){
                t = arr[start];
                arr[start] = arr[end];
                arr[end] = t;
                start++;
                end--;
            }
        }
    }
    
    // 调用方法
    signTitleDisplay2(TEST_STR);

    方法2,原理一样,只是在获取到字符数组后,对数组数据进行了翻转,前后位置颠倒,这样,集合里添加索引时就不用取倒了。 
    下面再说一种位运算


    public static final int[] FLAG_ARR = {1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };

    private void signTitleDisplay3(String titleDisplay){
        int newTitleDisplay = Integer.valueOf(titleDisplay, 2);
        for (int i = 0, count = FLAG_ARR.length; i < count; i++) {
            int value = FLAG_ARR[i] & newTitleDisplay;
            if (value != 0) {
                hotIndex.add(i);
            }
        }
    }
    // 调用方法
    signTitleDisplay3(TEST_STR);


    由于 titleDisplay :"11010010" 为字符串,首先要转换为2进制,这点很重要,不要单纯的转换为数字,要2进制。然后看FLAG_ARR数组,简单说,值为 0000 0001, 0000 0010, 0000 0100, 0000 1000 等等,只写了数据的后八位。用 & ,对应位上面值都为1值才为1,否则为0。不明白的可以复习一下位运算。
 
    相比较而言,大量数据时,方法3更好。首先位运算很快,同时节省了一个数组的消耗,再次如果给的 titleDisplay 是10位,也不必去判断截取,应为FLAG_ARR 里面没写,为0;新版本只需要在FLAG_ARR数组里增加对应的新值就 行了,而 方法1和方法2,还需要去改动方法,对比之下,三更好。













你可能感兴趣的:(Android,知识)