位运算在Android中的使用场景

来源:互联网 发布:日本好用护肤品知乎 编辑:程序博客网 时间:2024/05/17 07:10

首先说一下基本位运算知识:

位运算:位运算就是把数字用二进制表示之后,对每一位上0或者1的运算。

位运算总共只有5种运算:与、或、异或、左移、右移。如下表:

位运算

左移运算:

左移运算 左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0.比如:

00001010 << 2 = 00101000
10001010 << 3 = 01010000

右移运算:

 右移运算符m>>n表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。但右移时处理最左边位的情形要稍微复杂一点。这里要特别注意,如果数字是一个无符号数值,则用0填补最左边的n位。如果数字是一个有符号数值,则用数字的符号位填补最左边的n位。也就是说如果数字原先是一个正数,则右移之后再最左边补n个0;如果数字原先是负数,则右移之后在最左边补n个1.下面是堆两个8位有符号数作右移的例子:

00001010 >> 2 = 00000010
10001010 >> 3 = 11110001

关于移位的运算有这样的等价关系:

把整数右移一位和把整数除以2
a << = n ; //a左移一位等效于a = a * 2^n;

进制之间转换:

主要是2进制 8进制 16进制 之间的转换
16进制转换2进制 : 16进制每一位 对应 二进制中的四位
0xF4 ——– 1111 0100
8进制转换2进制 : 8进制每一位 对应二进制中的三位
364 ———011 110 100
10进制转换2进制:
这个我就不多说了一张图就明白
10to2
那么10 转换为2进制 从下向上读就是01010

位运算在Android中的使用场景

之前博客在介绍MeasureSpec和TypeValue的时候都一定程度说到到位运算,如果还不知道的话,可参考:

http://blog.csdn.net/wning1/article/details/64497446
http://blog.csdn.net/wning1/article/details/64137354

拿MesureSpec来说吧!子View需要复写onMeasure(),对于父布局推荐的大小和模式,可以通过MeasureSpec的getMode()和getSize()方法去获取,想象一下如果不使用位运算的这种形式,我们还可以采用那种方式?定义一个类对象包括int类型size 和int类型mode 两个参数也行。那么为啥要用位运算来计算呢?答案:节省内存。4个字节就能干的事情何必要8个字节去做呢

这几天我在Android源码又看到了一个位运算相关代码:

Fragment 如果要跳转到一个Activity并对Activity返回进行数据处理那么我们会选择调用startActivityForResult方法,以下为部分代码(compileSdkVersion 25):

Fragment 类  public void startActivityForResult(Intent intent, int requestCode) {        startActivityForResult(intent, requestCode, null);    }    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {        if (mHost == null) {            throw new IllegalStateException("Fragment " + this + " not attached to Activity");//mHost即为Fragment绑定的Activity对象        }        mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode, options);//调用FragmentActivity中的onStartActivityFromFragment    }FragmentActivity类   @Override        public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {            FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode);        }  public void startActivityFromFragment(Fragment fragment, Intent intent,            int requestCode) {        startActivityFromFragment(fragment, intent, requestCode, null);    }   public void startActivityFromFragment(Fragment fragment, Intent intent,            int requestCode, @Nullable Bundle options) {        mStartedActivityFromFragment = true;        try {            if (requestCode == -1) {                ActivityCompat.startActivityForResult(this, intent, -1, options); //默认startActivity 传递的requestCode == -1                return;            }            checkForValidRequestCode(requestCode);            int requestIndex = allocateRequestIndex(fragment);            ActivityCompat.startActivityForResult(                    this, intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), options);        } finally {            mStartedActivityFromFragment = false;        }    }  static void checkForValidRequestCode(int requestCode) {        if ((requestCode & 0xffff0000) != 0) {            throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");        }    }@Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        mFragments.noteStateNotSaved();        int requestIndex = requestCode>>16;        if (requestIndex != 0) {            requestIndex--;            String who = mPendingFragmentActivityResults.get(requestIndex);            mPendingFragmentActivityResults.remove(requestIndex);            if (who == null) {                Log.w(TAG, "Activity result delivered for unknown Fragment.");                return;            }            Fragment targetFragment = mFragments.findFragmentByWho(who);            if (targetFragment == null) {                Log.w(TAG, "Activity result no fragment exists for who: " + who);            } else {                targetFragment.onActivityResult(requestCode & 0xffff, resultCode, data);            }            return;        }        super.onActivityResult(requestCode, resultCode, data);    }

可以看到Fragment中调用startActivityForResult最终会调用到FragmentActivity中的startActivityFromFragment,如果requestCode!= -1 则调用checkForValidRequestCode进行code 数值判断,requestCode为int类型,requestCode & 0x ffff0000 如果不为0则说明requestCode高16位上至少1位为1也就是说数值肯定已经超过了65535。则会抛出参数非法异常,那么为什么不让用高16位呢?我们接向下看。 ((requestIndex + 1) << 16) + (requestCode & 0xffff) 重新做为了requestCode值,requestIndex + 1 向做移动了16位然后和旧的requetCode合并,那么现在新的requestCode的低16上存储的是真实的requestCode值,而高16则是存储的fragment的index,怪不得不让我们使用高16位呢。

在onActivityResult方法可以看到requestCode向右移动16位还原fragment的index,求出fragment如果fragment!=null则调用fragment的onActivityResult方法,否则回调给Activity。

ok,到这fragment这部分源码就已经分析完毕了,相信对位运算有了更加深刻的理解。

项目运用

以下为项目中蓝牙连接状态相关代码:

        /** 处于已断开状态时 */        public static final int UNCONNECT = 1;        /** 处于扫描状态时 */        public static final int SEARCHING = 1 << 1;        /** 处于正在连接时 */        public static final int CONNECTING = 1 << 2;        /** 处于已连接闲置状态时 */        public static final int IDLE = 1 << 3;        /** 处于正在断开状态时 */        public static final int DISCONNECTING = 1 << 4;        /** 处于工作状态时 */        public static final int WORKING = 1 << 5;        /** 处于闲置,或者工作状态集时 */        public static final int MASK_CONNECTED = IDLE | WORKING;        /** 处于扫描,或者连接,或者正在断开状态集时 */        public static final int MASK_BUSY_CONNECTING = SEARCHING | CONNECTING | DISCONNECTING;

我如果要想判断设备是否处于连接状态只需要 state & MASK_CONNECTED != 0,是否处于连接状态只需要state & MASK_CONNECTING != 0 即可。

想象一下传统的做法应该是所有的状态都定义成int类型,如果要判断是否处于连接状态,我们需要这样做 state == SEARCHING || state ==CONNECTING || state == DISCONNECTING .

孰优孰劣,一目了然,ok,关于位运算今天就记录到这。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 壹米滴答丢货怎么办 物流东西弄丢了怎么办 理赔款账号打错了怎么办 顺丰快递搞丢了怎么办 论文表格跨页了怎么办 网线突然没网了怎么办 室内门高门洞矮怎么办 路基填方土质含水率大怎么办 公路工程材料价格不予调差怎么办 桩基偏位60公分怎么办 定义的跨板受力筋长度不够怎么办 支座梁体预埋钢板忘记埋了怎么办 做nt小孩头朝下怎么办 简历上传的照片太大怎么办 本科毕业论文没写英文摘要怎么办 气泵储气罐有个小眼漏气怎么办 吸拉开关坏了怎么办 窗口数量已达上限怎么办 村土地原始台账没有怎么办 涂防晒霜后出汗怎么办 张拉千斤顶泄荷回油不到位怎么办 隧道二衬打到一半没混凝土怎么办 在左车道骑电动车撞到车怎么办 电镐钻头卡住了怎么办 玩具机器人无线遥控不了怎么办 电锤锤头卸不下来怎么办 打地基没打出硬土层怎么办 中标的项目经理没有B证怎么办 12306证件被注册过怎么办 政府3p项目不给钱怎么办 电气没考上国网怎么办 小区宽带业务被个人承包怎么办 高铁用户名忘了怎么办 昆山社保号是8位怎么办 高铁票误了时间怎么办 动车票没赶上车怎么办 铁路用户名已存在要怎么办 铁路12306用户名忘了怎么办 铁路12306的用户名忘了怎么办 铁路12306注册名已存在怎么办 12306账号密码忘记了怎么办