位运算在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进制:
这个我就不多说了一张图就明白
那么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,关于位运算今天就记录到这。
- 位运算在Android中的使用场景
- 位运算使用场景
- 位运算在Android Flag中的巧妙使用
- 位与运算在iOS中的使用
- Android中的位运算
- Android中的位运算
- Java位运算的使用场景
- java位运算符的使用场景
- 关于位运算在权限配置及类似场景中的应用
- 位运算在算法编程中的使用技巧
- 位运算在算法编程中的使用技巧
- 位运算在算法题中的使用(C++)
- 位与运算符 在权限中的使用
- RxJava zip操作符在Android中的实际使用场景
- RxJava zip操作符在Android中的实际使用场景
- RxJava zip操作符在Android中的实际使用场景
- Java位运算在程序设计中的使用:位掩码(BitMask)
- Java位运算在程序设计中的使用:位掩码(BitMask)
- 多线程-线程控制之守护线程
- js的时间格式化工具类
- Struts控制器实现
- POJ 1590 Palindromes 笔记
- 【微营销】第9天 微营销实战技巧之如何做产品宣传与推广
- 位运算在Android中的使用场景
- 广播接收者案例
- leetcode-3. Longest Substring Without Repeating Characters
- 单链表逆置
- Android开发进阶——使用Dagger2
- 实现拦截一条有序广播
- 使用一个ContentProvider操作多张表
- sql server中char和varchar的区别
- React---状态和生命周期