位运算在Android中的使用场景

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

位运算:位运算就是把数字用二进制表示之后,对每一位上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,关于位运算今天就记录到这。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值