├── LICENSE ├── README.md ├── article ├── Android 开发过程中遇到的问题.md ├── Android 窗体.md ├── CreateBlog.md ├── Interview-1.md ├── Interview-2.md └── RxJava-Operator-summary.md └── utils └── InsecureSHA1PRNGKeyDerivator.java /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevelopNote 2 | 3 | ## This is some of my notes that I've been working on during the development process 4 | -------------------------------------------------------------------------------- /article/Android 开发过程中遇到的问题.md: -------------------------------------------------------------------------------- 1 | 1. Fragment 的 onAttach(Activity) 方法在 API 23 之后被弃用,改为 onAttach(Context) ,所以针对不同的 SDK 版本使用不同的方法。例子: 2 | ``` 3 | 4 | @TargetApi(23) 5 | @Override 6 | public void onAttach(Context context) { 7 | super.onAttach(context); 8 | // 执行操作 9 | } 10 | 11 | /* 12 | * Deprecated on API 23 13 | * Use onAttachToContext instead 14 | */ 15 | @SuppressWarnings("deprecation") 16 | @Override 17 | public void onAttach(Activity activity) { 18 | super.onAttach(activity); 19 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 20 | // 执行操作 21 | } 22 | } 23 | ``` 24 | Fragment 中,如果要获取 Activity 对象,不建议调用 getActivity() ,而是在 onAttach() 中将 Context 对象强转为 Activity 对象。 25 | 26 | 2. AtomicLong 和 Long 的区别是? 27 | 28 | AtomicLong 是线程安全的,Long 是线程不安全的。 29 | 30 | 3. GestureDetector 的作用是什么? 31 | 32 | GestureDetector 是一个手势监听识别的类,其有两个接口 OnGestureListener,OnDoubleTapListener 和一个静态内部类 SimpleOnGestureListener。这个内部类实现了提供的两个接口。具体实例如下: 33 | ``` 34 | GestureDetector detector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() { 35 | //需要处理什么手势,重写相应的回调方法 36 | @Override 37 | public boolean onDoubleTap(MotionEvent e) { 38 | //双击的回调 39 | return super.onDoubleTap(e); 40 | } 41 | }); 42 | 43 | view.setOnTouchListener(new View.OnTouchListener() { 44 | @Override 45 | public boolean onTouch(View v, MotionEvent event) { 46 | detector.onTouchEvent(event); 47 | return false; 48 | } 49 | }); 50 | ``` 51 | 4. Android 中在 WebView 中访问微信的支付页面,打不开的问题 52 | 53 | ``` 54 | mWebview.setWebViewClient(new WebViewClient() { 55 | @Override 56 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 57 | // 如下方案可在非微信内部WebView的H5页面中调出微信支付 58 | if (url.startsWith("weixin://wap/pay?")) { 59 | Intent intent = new Intent(); 60 | intent.setAction(Intent.ACTION_VIEW); 61 | intent.setData(Uri.parse(url)); 62 | startActivity(intent); 63 | return true; 64 | } 65 | view.loadUrl(url); 66 | return true; 67 | } 68 | 69 | @Override 70 | public void onPageFinished(WebView view, String url) { 71 | // 这个方法有可能会多次执行 72 | super.onPageFinished(view, url); 73 | } 74 | }); 75 | ``` 76 | 5. Activity 的生命周期 A 启动 B 的生命周期流程 77 | 78 | A:onCreate->A:onStart->A:onResume->A:onPause->B:onCreate->B:onStart->B:onResume->A:onStop 79 | 80 | 6. ToolBar 左侧有一个默认的左边距,不去掉导致与设计页面不符 81 | 82 | ``` 83 | 通过给 ToolBar 设置 app:contentInsetStart="0dp" 属性可以去除默认的左边距 84 | ``` 85 | 7. ARouter 设置了 withFlags 必须需要在 navigation 中设置 Activity,不然会报 Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. 如果不添加 withFlags,ARouter 会自动给不是 Activity 的添加 FLAG_ACTIVITY_NEW_TASK flag。 86 | 87 | ``` 88 | ARouter.getInstance().build(RouterConfig.APPLICATION_ACTIVITY).withFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).navigation(Actvity.this); 89 | ``` 90 | 8. View 的 scrollTo() 和 scrollBy() 方法移动方向 91 | 92 | ``` 93 | 当水平方向为正值,向左侧移动,为负值向右侧移动。 94 | 当垂直方向为正值,向上移动,为负值向下移动。 95 | ``` 96 | 9.Webview 的 clearHistory() 方法不起作用的解决 97 | 98 | ``` 99 | clearHistory() 作用是调用方法时,清空当前页面之前的所有记录 100 | 101 | 方法1:postDelayed 延时调用 102 | webView.postDelayed(new Runnable() { 103 | @Override 104 | public void run() { 105 | webView.clearHistory(); 106 | } 107 | }, 1000); 108 | 109 | 方法2:在 onPageFinished 方法中去调用 clearHistory 方法 110 | ``` 111 | 10. Android 7.0 以上 AES 加密报错 java.security.NoSuchAlgorithmException: class configured for SecureRandom (provider: Crypto) cannot be found. 112 | 113 | [InsecureSHA1PRNGKeyDerivator 工具类的下载地址](https://github.com/shrotybin/DevelopNote/blob/master/utils/InsecureSHA1PRNGKeyDerivator.java) 114 | ``` 115 | 解决方法 116 | private static byte[] getRawKey(byte[] seed) throws Exception { 117 | if (Build.VERSION.SDK_INT >= 24) {//对 9.0 以上的进行处理 118 | byte[] rawKey = InsecureSHA1PRNGKeyDerivator.deriveInsecureKey(seed, 32); 119 | return rawKey; 120 | } else { 121 | KeyGenerator kgen = KeyGenerator.getInstance(AES); 122 | //for android 123 | SecureRandom sr = null; 124 | // 在4.2以上版本中,SecureRandom获取方式发生了改变 125 | if (android.os.Build.VERSION.SDK_INT >= 17) { 126 | sr = SecureRandom.getInstance(SHA1PRNG, "Crypto"); 127 | } else { 128 | sr = SecureRandom.getInstance(SHA1PRNG); 129 | } 130 | // for Java 131 | // secureRandom = SecureRandom.getInstance(SHA1PRNG); 132 | sr.setSeed(seed); 133 | kgen.init(128, sr); //256 bits or 128 bits,192bits 134 | //AES中128位密钥版本有10个加密循环,192比特密钥版本有12个加密循环,256比特密钥版本则有14个加密循环。 135 | SecretKey skey = kgen.generateKey(); 136 | byte[] raw = skey.getEncoded(); 137 | return raw; 138 | } 139 | } 140 | ``` 141 | 11. 在 Android P 上弹窗提示 Detected problems with API compatibility(visit g.co/dev/appcompat for more info) 142 | 143 | ``` 144 | Android P 后谷歌限制了开发者调用非官方公开 API 方法或接口,如果通过反射调用了非官方的 API 就会提示这个弹窗,建议查找代码去掉相应的反射。 145 | ``` 146 | 12. Android 9.0 网络请求报 java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy 147 | 148 | ``` 149 | 在Android P 系统的设备上,如果应用使用的是非加密的明文流量的 http 网络请求,则会导致该应用无法进行网络请求,https 则不会受影响,同样地,如果应用嵌套了 webview,webview 也只能使用 https 请求。 150 | 151 | 解决办法:1.将请求替换未 https 152 | 2. 在 res 下新增一个 xml 目录,然后创建一个名为:network_security_config.xml 文件(名字自定) ,内容如下,大概意思就是允许开启 http 请求 153 | 154 | 155 | 156 | 157 | 158 | 159 | 然后在APP的AndroidManifest.xml文件下的application标签增加以下属性 160 | 161 | 162 | 167 | ``` 168 | 13. Android 9.0 上报 ClassNotFoundException: Didn't find class "org.apache.http.conn.scheme.SchemeRegistry 169 | 170 | [官方给出的解释](https://developer.android.google.cn/about/versions/pie/android-9.0-changes-28) 171 | ``` 172 | 在 Android 6.0 中,我们取消了对 Apache HTTP 客户端的支持。 从 Android 9 开始,默认情况下该内容库已从 bootclasspath 中移除且不可用于应用。 173 | 174 | 解决办法:在 AndroidManifest.xml 的 application 节点下添加以下内容: 175 | 176 | 177 | ``` 178 | 14. Android 使用三方库一般都需要在 Application 中做一些初始化,使用 ContentProvider,可以将初始化放到库中自定义的 ContentProvider 中让主 APP 使用,因为 ContentProvider 的初始化是在 Application 之中进行的。 179 | 15. Android 8.0 某些手机会报 java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation 180 | 181 | ``` 182 | 方案 1:去除 android:screenOrientation="portrait",或者不调用设置方向的代码 183 | 方案 2:设置 false 184 | false 185 | ``` 186 | 16. Android 原生 webview 加载出现页面部分内容不显示,日志报了 This request has been blocked; the content must be served over HTTPS. 187 | 188 | ``` 189 | 这个是加载的地址是https的,一些资源文件使用的是http方法的,从安卓4.4之后对webview安全机制有了加强,webview里面加载https url的时候,如果里面需要加载http的资源或者重定向的时候,webview会block页面加载。需要设置MixedContentMode。 190 | 191 | 如下设置: 192 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 193 | // 5.0以上允许加载http和https混合的页面(5.0以下默认允许,5.0+默认禁止) 194 | webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); 195 | } 196 | 197 | ``` 198 | 17. 当一个类的方法被 protected 修饰,只有在同一个包下才能被调用,要想在别的包下调用可以用匿名内部类的方式 199 | 200 | ``` 201 | Gson 的 TypeToken 构造函数是 protected。 202 | TypeToken> list = new TypeToken>() {}; 203 | ``` 204 | 18. 数字保留两位小数的方法 205 | 206 | ``` 207 | DecimalFormat decimalFormat = new DecimalFormat("0.00"); 208 | String format = decimalFormat.format(mPrice); 209 | ``` 210 | 19. 报错信息:Bitmap: Error, cannot access an invalid/free'd bitmap here! 211 | 212 | ``` 213 | debug 后也发现是在 nativeColorSpaceCopy 这里出问题,因此不要手动 recycle() 214 | 去掉手动调用 bitmap 的 recycle() 方法即可。 215 | ``` 216 | 20. Java 集合的总结 217 | 218 | ``` 219 | jdk 1.6中如下,别的版本有所不同 220 | HashMap 的默认大小为16,阀值为0.75,扩容大小为(当前大小+当前大小*0.75),线程不安全,数据结构为数组加单向链表组成的哈希表结构,键值对允许为null。 221 | HashTable 的默认大小为11,阀值为0.75,扩容大小为(当前大小*2+1),线程安全,数据结构为数组加单向链表组成的哈希表结构,键值对不允许为null。 222 | ArrayList 的默认大小为10,扩容大小为(当前大小*1.5+1),线程不安全,数据结构为动态数组,可以添加null。 223 | LinkedList 的默认大小为10,因为是双向链表所以无需扩容,线程不安全,可以添加null。 224 | HashSet 内部使用了 HashMap 的 Key 来存储数据,他的数据不能重复。 225 | ``` 226 | 21. Java 内部类的问题 227 | 228 | ``` 229 | 1.内部类中不能包含静态方法,必须为静态内部类包含静态方法。 230 | 2.静态内部类不能直接直接访问外部类的非静态属性 231 | ``` 232 | 22. Android 某些机型拍照出来的照片默认旋转了90度,如果我们要加载图片应该先获取图片旋转了多少度,然后再旋转回去显示 233 | ``` 234 | 获取图片旋转的角度 235 | public static int readPictureDegree(String path) { 236 | int degree = 0; 237 | try { 238 | ExifInterface exifInterface = new ExifInterface(path); 239 | int orientation = exifInterface.getAttributeInt( 240 | ExifInterface.TAG_ORIENTATION, 241 | ExifInterface.ORIENTATION_NORMAL); 242 | switch (orientation) { 243 | case ExifInterface.ORIENTATION_ROTATE_90: 244 | degree = 90; 245 | break; 246 | case ExifInterface.ORIENTATION_ROTATE_180: 247 | degree = 180; 248 | break; 249 | case ExifInterface.ORIENTATION_ROTATE_270: 250 | degree = 270; 251 | break; 252 | } 253 | } catch (IOException e) { 254 | e.printStackTrace(); 255 | return degree; 256 | } 257 | return degree; 258 | } 259 | ``` 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /article/Android 窗体.md: -------------------------------------------------------------------------------- 1 | # Android 窗体 2 | 3 | ## Activity 4 | 5 | ### 通过 ActivityThread 中的 performLaunchActivity 方法 创建了对应的 Activity,先调用了 Activity 的 attach 方法,再通过 mInstrumentation 调用了 Activity 的 onCreate 方法 6 | 7 | ### Windows 8 | 9 | - Windows 是有个抽象类,它的唯一实现类是 PhoneWindows 类 10 | - WindowsManager 11 | 12 | - 如何创建 13 | 14 | - 在 Activity 的 attach 方法中创建完 PhoneWindows 赋给 Windows,调用 Windows 的 setWindowManager 方法创建了WindowsManager,这个方法中是通过 WindowManagerImpl 的 createLocalWindowManager() 方法创建的 15 | 16 | 在 Windows 的 setWindowManager 方法中,首先获取系统启动注册的 WindowManager,系统是通过 WindowManagerImpl(ctx) 创建的,我们拿到 WindowManager,通过 ((WindowManagerImpl)wm).createLocalWindowManager(windows) 方法创建了一个新的 WindowsManagerImpl,与 Windows 相关联 17 | 18 | - WindowsManager 和 DecorView 是在什么时候进行绑定的 19 | 20 | - ActivityThread 中启动 Activity 时候先调用了 handleLaunchActivity 方法,在这个方法中调用完 performLaunchActivity 方法,又调用了 handleResumeActivity 方法,进行绑定的过程是在 handleResumeActivity 方法中,通过WindowsManager 的 addView 方法把 DecorView 绑定 21 | 22 | - WindowsManager 是一个接口,具体的实现类是 WindowManagerImpl,它是通过 WindowManagerGlobal 代理实现 23 | - WindowManagerGlobal 24 | 25 | - 其内部通过 ViewRootImpl 来管理 View 26 | - ViewRootImpl 27 | 28 | ### IBinder : mToken 29 | 30 | ## PhoneWindows 31 | 32 | ### 如何创建的 33 | 34 | - 在 Activity 中的 attach 方法中创建了 PhoneWindows 35 | 36 | ### DecorView 37 | 38 | - 作用 39 | 40 | - 添加标题栏和内容,PhoneWindows 是它的载体 41 | 42 | - 如何创建的 43 | 44 | - 它继承了 FrameLayout,通过 PhoneWindows 中的 generateDecor 方法创建的 45 | 46 | - 不同版本问题 47 | 48 | - 从 Android 7.0 开始 DecorView 是一个单独类,之前的版本 DecorView 是PhoneWindows 的内部类 49 | 50 | ### mContentParent 51 | 52 | - 通过 generateLayout(DecorView decor) 方法把返回值赋给 mContentParent,mContentParent 是我们的内容区域,在这个方法中,会获取用户设置的主题等属性,因此 requesetFeature 方法必须在 setContentView 方法之前调用 -------------------------------------------------------------------------------- /article/CreateBlog.md: -------------------------------------------------------------------------------- 1 | # 快速创建一个属于自己的博客 2 | 3 | 在清明三天假期中利用休息时间模仿 [GcsSloop](http://www.gcssloop.com/) 的博客创建了一个属于自己的博客,希望自己以后可以在这个 Blog 上记录一些开发中的问题。 4 | 这个 Blog 是用 Coding 和 Jekyll 搭建的,整体来说还是比较容易的。[Coding](https://coding.net/) 是一个类似 [GitHub](https://github.com/) 的代码托管。 5 | 之所以利用 Coding 是因为它的访问速度在国内比 GitHub 要快许多。 6 | 7 | 首先在 [Coding](https://coding.net/) 上创建一个属于自己的账号,在创建的账号下新建一个项目。 8 | 9 | ![](http://ww1.sinaimg.cn/large/ee14e49dly1fec88omlpkj219q0wmae4.jpg) 10 | 11 | 按照上图创建好了项目 12 | 13 | 使用 git 把项目 clone 到本地。这里我使用的 Jekyll 的主题是使用 GcsSloop的[Gcs-Vno-Jekyll](https://github.com/GcsSloop/Gcs-Vno-Jekyll) , 14 | Gcs-Vno-Jekyll 是 GcsSloop 基于 onevcat 大神的 [OneV-s-Den](https://github.com/onevcat/OneV-s-Den) 修改而来的. 15 | 16 | 我们把 [Gcs-Vno-Jekyll](https://github.com/GcsSloop/Gcs-Vno-Jekyll) clone 到之前项目的目录下,把所有文件添加到版本库推送到 Coding.net。 17 | 在项目的「Pages 服务」设置中,选择部署来源为 master 分支,点击「保存」按钮。 稍等片刻即可完成部署并通过 {user_name}.coding.me/{project_name} 访问您的网站. 18 | 19 | 这里我用的 WebStorm 打开之前的项目,项目的结构如下图 20 | 21 | ![](http://ww1.sinaimg.cn/large/ee14e49dly1fec9ptk55pj20ju0nu40i.jpg) 22 | 23 | 然后修改 _config.yml 文件中的内容就可以改变主页中的信息,如下图: 24 | 25 | ![](http://ww1.sinaimg.cn/large/ee14e49dly1fec9ynmmaoj21ee0todn0.jpg) 26 | 27 | 修改其中的内容就可以改变首页中的信息 28 | 29 | 修改头像和背景图需要修改 assets/siteinfo 下的 avatar 和 background-cover 即可。 30 | 31 | 修改网址图标则需要修改 _includes/head.html 中的: 32 | 33 | ![](http://ww1.sinaimg.cn/large/ee14e49dly1feca5t21yyj21c0036gnb.jpg) 34 | 35 | 修改上图中的两个 href 。这里我利用的新浪图床生成的图片地址。 36 | 37 | 最后需要添加文章是在 _posts 下创建 年-月-日-描述.md格式的文章,内容可以如下图: 38 | 39 | ![](http://ww1.sinaimg.cn/large/ee14e49dly1fecadc0589j21k00zsdqh.jpg) 40 | 41 | 修改其中的内容即可,修改完之后push到master分支。一般过上几分钟去自己的 blog {user_name}.coding.me/{project_name} 访问即可看到效果。 42 | 43 | 希望大家都能创建一个属于自己的博客,分享更多的技术文章,与大家共同进步!!! 44 | 45 | ****** 46 | -------------------------------------------------------------------------------- /article/Interview-1.md: -------------------------------------------------------------------------------- 1 | # 面试经历 2 | 3 | ## 1. 屏幕适配都是怎们去做的 4 | 1. 尽量使用相对布局(RelativeLayout),禁用绝对布局(AbsoluteLayout)。LinearLayout使用"wrap_content"和"match_parent"已经可以构建出不错的布局。但是LinearLayout无法准确地控制子视图之间的位置关系,只能简单的一个挨着一个地排列,所以对于适配屏幕应该根据情况适当选择。 5 | 2. 根据屏幕的配置来加载相应的UI布局。 6 | * 尺寸限定符:根据不同的屏幕尺寸加载不同的布局(这种方式只适合Android 3.2版本之前)。 7 | * 最小宽度限定符:根据设定的不同宽度,不同的屏幕宽度加载不同的布局(Android 3.2版本之后引入的,推荐使用)。 8 | * 屏幕方向限定分:根据屏幕的方向加载不同的布局。 9 | 3. 组件的宽高使用dp,字体的大小使用sp 10 | 4. 使用"wrap_content"、"match_parent"和"weight“来控制视图组件的宽度和高度,尽量少使用dp直接控制宽高 11 | 5. 对于图片在不同屏幕密度上显示相同的像素效果,使用.9图 12 | 6. 使用百分比适配 13 | 7. 不同分辨率使用多套图片资源,考虑APK太大,可以只用xhdpi 14 | 15 | ## 2. equals 和 == 的区别 16 | == 用来比较基本类型,equals 一般用来比较引用类型的。使用==比较引用类型,比较的是对象的地址。自定义对象的 euqals 方法内部使用的 == 来比较的,继承自Object。如果自定义的对象要比较,可以重写 equals 方法,重写 equals 方法注意必须先要重写 hashCode 方法(这一点给忘记了。。。)。 17 | ## 3. MVC和MVP优缺点 18 | ### MVC: 19 | * View:视图界面,对应于布局文件 20 | * Model:数据的封装和保存,业务逻辑和实体模型 21 | * Controller:业务逻辑,对应于Activity、Fragment等 22 | 23 | ### MVC的优点: 24 | * 比较容易理解,对于一些小的项目维护和迭代比较方便 25 | 26 | ### MVC的缺点: 27 | * Activity 即充当了 View 又充当了 Controller,分工不明确 28 | * 对于一些复杂的功能,Activity内的代码太多(多达几千行),难以维护和迭代 29 | * View和Model之间相互可知,存在耦合 30 | * 不利于单元测试 31 | 32 | ### MVP: 33 | * View:对应于Activity,负责View的绘制以及与用户交互 34 | * Model:依然是业务逻辑和实体模型 35 | * Presenter:负责完成View于Model间的交互 36 | 37 | ### MVP优点: 38 | * 解耦,三个层级之间互相不知道各自的内容 39 | * 各个层级之间结构清晰,易于维护 40 | * 业务逻辑单独出来,易于单元测试 41 | 42 | ### MVP缺点: 43 | * 接口比较多 44 | * 在一些小的项目上使用反而没有MVC开发快速 45 | 46 | ## 4. 重写和重载的不同 47 | ### 重写: 48 | * 父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖 49 | * 若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类 50 | * 子类函数的访问修饰权限不能少于父类的 51 | 52 | ### 重写的规则 53 | * 参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载 54 | * 返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载 55 | * 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private) 56 | * 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常 57 | 58 | ### 重载 59 | * 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载Overloading是一个类中多态性的一种表现。 60 | * Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。 61 | * 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。 62 | 63 | ### 重载的规则 64 | * 必须具有不同的参数列表; 65 |  * 可以有不同的返回类型,只要参数列表不同就可以了; 66 | * 可以有不同的访问修饰符; 67 | * 可以抛出不同的异常; 68 | 69 | ### 重写和重载的不同之处 70 | ##### 重写多态性起作用,对调用被重载过的方法可以大大减少代码的输入量,同一个方法名只要往里面传递不同的参数就可以拥有不同的功能或返回值。用好重写和重载可以设计一个结构清晰而简洁的类,可以说重写和重载在编写代码过程中的作用非同一般. 71 | ## 5. 栈和队列的区别 72 | ### 队列:是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。 73 | ### 栈:是限定只能在表的一端进行插入和删除操作的线性表。 74 | 75 | 栈和队列的区别如下: 76 | 77 | * 规则不同 78 | 1. 队列:先进先出 79 | 2. 栈:先进后出 80 | * 对插入和删除操作的限定不同 81 | 1. 队列:只能在表的一端进行插入,并在表的另一端进行删除; 82 | 2. 栈:只能在表的一端插入和删除。 83 | * 遍历数据速度不同 84 | 1. 队列:基于地址指针进行遍历,而且可以从头部或者尾部进行遍历,但不能同时遍历,无需开辟空间,因为在遍历的过程中不影响数据结构,所以遍历速度要快; 85 | 2. 栈:只能从顶部取数据,也就是说最先进入栈底的,需要遍历整个栈才能取出来,而且在遍历数据的同时需要为数据开辟临时空间,保持数据在遍历前的一致性。 86 | 87 | ## 6. List、Map和Set的不同 88 | 这一块的内容比较多,推荐一个链接大家直接看吧!!!。 这一块的内容比较重要的,基本面试都会问到,而且会结合到数据结构的内容,大家平时多看看相关的内容,最好可以深入到源码。 89 | ## 7. 创建线程有几种方法 90 | Java中创建线程共三种方法: 91 | 92 | * 继承Thread类创建线程类 93 | 1. 定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。 94 | 2. 创建Thread子类的实例,即创建了线程对象。 95 | 3. 调用线程对象的start()方法来启动该线程。 96 | * 通过Runnable接口创建线程类 97 | 1. 定义 Runnable 接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。 98 | 2. 创建 Runnable 实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。 99 | 3. 调用线程对象的start()方法来启动该线程。 100 | * 通过Callable和Future创建线程(这种方法使用的较少) 101 | 1. 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。 102 | 2. 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。 103 | 3. 使用FutureTask对象作为Thread对象的target创建并启动新线程。 104 | 4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值 105 | 106 | 各个创建线程的优缺点: 107 | 108 | Runnable、Callable优势是: 109 | 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。 110 | 111 | 缺点是: 112 | 编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。 113 | 114 | 继承Thread类的方式的优势是: 115 | 编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。 116 | 117 | 缺点是: 118 | 线程类已经继承了Thread类,所以不能再继承其他父类。 119 | ## 8. 线程间通信有几种方法 120 | * 通过发送广播 121 | * Activity的runOnUiThread(Runnable r)方法(内部借助Handler) 122 | * View对象的post(Runnable r)或postDelay(Runnable r)方法(内部借助Handler) 123 | * Handler实现线程间的通信 124 | * 使用AsyncTask(内部封装了Handler) 125 | * 使用EventBus、RxJava等框架 126 | 127 | ## 9. 进程通信有几种方法 128 | * Android的四大组件都可以进行进程通信 129 | * 使用AIDL进行进程通信 130 | * 通过隐式Intent 131 | * 文件共享,对同一个文件先后进行读写,但要注意同步 132 | * 使用Socket,服务中定义 ServerSocket 来监听端口,客户端使用 Socket 来请求端口,连通后就可以进行通信 133 | 134 | ## 10. Service保活有什么方法 135 | * 提高服务的优先级 136 | * 使用双服务守护进程 137 | * 在屏幕上保留一个像素点 138 | 这些方法都没发达到完全保活,不同的系统上可能没发保证不被杀死。而且Service一直在运行时比较消耗电量的,Google也不建议开发者让Service一直运行。 139 | 140 | ## 11. Activity和Fragment通信有那几种方法 141 | * Fragment和Fragment通信,一个Fragment可以直接调另一个Fragment中的方法 142 | * Activity和Fragment通信可以使用接口回调的方式 143 | * 两个Fragment通信可以使用广播 144 | * Fragment可以直接调用Activity里public的方法 145 | 146 | ## 12. View的绘制流程 147 | View的绘制流程大致分为三部:Measure -> Layout -> Draw。具体每个过程大家可以详细的了解下具体的过程。这一块问了之后一般都会问到自定义View。 148 | ## 13. 事件分发流程 149 | 1. 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。 150 | 2. 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。 151 | 3. 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。 152 | 4. 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。 153 | 5. OnTouchListener优先于onTouchEvent()对事件进行消费。 154 | 155 | 这个问题基本是每次面试都会问到的。 156 | 157 | ## 14. Handler机制 158 | 从Handler中获取一个消息对象,把数据封装到消息对象中,通过Handler的send…方法把消息push到MessageQueue队列中。 Looper对象会轮询MessageQueue队列,把消息对象取出。 通过dispatchMessage分发给Handler,再回调用Handler实现的handleMessage方法处理消息。 159 | 160 | 这个是一个大概的描述,在详细的流程大家可以去搜索下,网上相关的介绍非常多,而且很多都是带有图片分析,更容易理解。这个在面试中也是经常问到的。 161 | 162 | ## 15. TCP和UDP不同 163 | 1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接 164 | 2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付 165 | 3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等) 166 | 4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信 167 | 5. TCP首部开销20字节;UDP的首部开销小,只有8个字节 168 | 6. TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道 169 | 170 | ## 16. 内存泄露有哪些 171 | 1. 集合类导致泄露,集合内添加了元素,一直未删除 172 | 2. 使用单例造成泄漏,传入了Activity造成 173 | 3. 匿名内部类/非静态内部类和异步线程 174 | 4. Handler 造成的内存泄漏,Handler 发送的 Message 尚未被处理,则该 Message 及发送它的 Handler 对象将被线程 MessageQueue 一直持有。 175 | 5. 资源未关闭造成的内存泄漏 176 | 6. Bitmap 没调用 recycle()方法,Bitmap 对象在不使用时,我们应该先调用 recycle() 释放内存。 177 | 178 | 对于内存泄漏可以集成 LeakCanary 分析出什么地方存在内存泄漏,及时修改。 179 | 180 | ## 17. 性能优化如何做 181 | 1. 布局的层级不要太深,如过嵌套过多,渲染比较慢 182 | 2. 使用 Leakcanary 工具定位分析内存泄漏 183 | 3. 图片优化,尽量使用比较小的图片,图片要缓存和复用 184 | 4. 存储的集合对象及时清理 185 | 5. 使用IntentService代替Service 186 | 187 | 这个相关的方法特别多,我就不一一列举了,大家有需要的去搜索吧!!! 这个问题每次面试都问到 188 | ## 18. 图片缓存的原理 189 | Android 图片的缓存有三级缓存:内存、文件、网络。 190 | 191 | 图片加载这一块现在我们用的都是第三方的框架,很少使用自己写的缓存,要想知道具体的原理,大家可能需要研究下图片加载框架的内部实现原理了,大概知道下三级缓存是怎么做的,心里有个数,面试的时候能大概说出来就行。查看框架的源码还是十分重要,公司都比较看重员工的自学能力。 192 | ## 19. 线程池内部是如何实现的 193 | 1. 判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。 194 | 2. 线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。 195 | 3. 判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。 196 | 197 | ## 20. Mediaplay的生命周期 198 | 199 | ### Mediaplay的生命周期顺序是:Idle -> Initialized -> Prepared -> Preparing -> Started -> Paused -> Stop -> PlaybackCompleted -> End -> Error 200 | 201 | * Idle:当使用new()方法创建一个MediaPlayer对象或者调用了其reset()方法时,该MediaPlayer对象处于idle状态。这两种方法的一个重要差别就是:如果在这个状态下调用了getDuration()等方法(相当于调用时机不正确),通过reset()方法进入idle状态的话会触发OnErrorListener.onError(),并且MediaPlayer会进入Error状态;如果是新创建的MediaPlayer对象,则并不会触发onError(),也不会进入Error状态。 202 | 203 | * End: 通过release()方法可以进入End状态,只要MediaPlayer对象不再被使用,就应当尽快将其通过release()方法释放掉,以释放相关的软硬件组件资源,这其中有些资源是只有一份的(相当于临界资源)。如果MediaPlayer对象进入了End状态,则不会在进入任何其他状态了。 204 | 205 | * Initialized:这个状态比较简单,MediaPlayer调用setDataSource()方法就进入Initialized状态,表示此时要播放的文件已经设置好了。 206 | 207 | * Prepared:初始化完成之后还需要通过调用prepare()或prepareAsync()方法,这两个方法一个是同步的一个是异步的,只有进入Prepared状态,才表明MediaPlayer到目前为止都没有错误,可以进行文件播放。 208 | 209 | * Preparing:这个状态比较好理解,主要是和prepareAsync()配合,如果异步准备完成,会触发OnPreparedListener.onPrepared(),进而进入Prepared状态。 210 | 211 | * Started:显然,MediaPlayer一旦准备好,就可以调用start()方法,这样MediaPlayer就处于Started状态,这表明MediaPlayer正在播放文件过程中。可以使用isPlaying()测试MediaPlayer是否处于了Started状态。如果播放完毕,而又设置了循环播放,则MediaPlayer仍然会处于Started状态,类似的,如果在该状态下MediaPlayer调用了seekTo()或者start()方法均可以让MediaPlayer停留在Started状态。 212 | 213 | * Paused:Started状态下MediaPlayer调用pause()方法可以暂停MediaPlayer,从而进入Paused状态,MediaPlayer暂停后再次调用start()则可以继续MediaPlayer的播放,转到Started状态,暂停状态时可以调用seekTo()方法,这是不会改变状态的。 214 | 215 | * Stop:Started或者Paused状态下均可调用stop()停止MediaPlayer,而处于Stop状态的MediaPlayer要想重新播放,需要通过prepareAsync()和prepare()回到先前的Prepared状态重新开始才可以。 216 | 217 | * PlaybackCompleted:文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并会触发OnCompletionListener的onCompletion()方法。此时可以调用start()方法重新从头播放文件,也可以stop()停止MediaPlayer,或者也可以seekTo()来重新定位播放位置。 218 | 219 | * Error:如果由于某种原因MediaPlayer出现了错误,会触发OnErrorListener.onError()事件,此时MediaPlayer即进入Error状态,及时捕捉并妥善处理这些错误是很重要的,可以帮助我们及时释放相关的软硬件资源,也可以改善用户体验。通过setOnErrorListener(android.media.MediaPlayer.OnErrorListener)可以设置该监听器。如果MediaPlayer进入了Error状态,可以通过调用reset()来恢复,使得MediaPlayer重新返回到Idle状态。 220 | 221 | ## 21. 图片加载框架volley、glider的实现 222 | 223 | ## 22. 插件化和热修复的原理 224 | ## 23. UI层数据和服务器数据不一样,如何解析数据 225 | ## 24. 涟漪的自定义View实现 226 | ## 25. 数据库使用sqllite还是provider,哪一个会更好一些 227 | ## 26. App自动更新如何实现,断点续传的原理 228 | ## 27. Https和Http的区别,Http如何保障访问安全 229 | 230 | 231 | ## 总结 232 | 这个文章里面总结面试中遇到的问题,答案基本上都来自网络,如有侵犯可联系我,我会加上链接地址。另外有些没有给出答案,大家可以自己总结。如果答案存在问题或者有需要补充的大家可以提 Issues 233 | 234 | 参考: 235 | 236 | 237 | ****** 238 | -------------------------------------------------------------------------------- /article/Interview-2.md: -------------------------------------------------------------------------------- 1 | # 最近面试中遇到的题目: 2 | ## 1. 屏幕旋转时 Activity 的生命周期变化(测试Android版本为7.1.1,版本号为25) 3 | 4 | configChanges 是默认的情况下,由竖屏切换为横屏时生命周期时: 5 | 6 | onPause()——>onStop()——>onDestroy()——>onCreate()——>onStart()——>onResume() 7 | 8 | 再有横屏切换为竖屏时,生命周期为: 9 | 10 | onPause()——>onStop()——>onDestroy()——>onCreate()——>onStart()——>onResume() 11 | 12 | configChanges 设置为 "orientation|keyboardHidden" 时,由竖屏切换为横屏时生命周期为: 13 | 14 | onPause()——>onStop()——>onDestroy()——>onCreate()——>onStart()——>onResume() 15 | 16 | 再由横屏切换为竖屏时,生命周期为: 17 | 18 | onPause()——>onStop()——>onDestroy()——>onCreate()——>onStart()——>onResume() 19 | 20 | configChanges 设置为 "orientation|keyboardHidden|screenSize" 时,由竖屏切换为横屏时生命周期为: 21 | 22 | onConfigurationChanged() 23 | 24 | 再由横屏切换为竖屏时,生命周期为: 25 | 26 | onConfigurationChanged() 27 | 28 | ## 2. Fragment 切换的方式有几种,它的生命周期变化 29 | 参考链接: 30 | 31 | ## 3. Android 中动画的原理 32 | 参考链接: 33 | 34 | ## 4. 在网页中启动APP 35 | 参考链接: 36 | 37 | ## 5. Android 中序列画的方式由哪些,有什么区别 38 | 39 | 序列化为 Serializable 和 Parcelable 40 | 41 | | 区别 | Serializable | Parcelable 42 | | 所属API |JAVA API | Android SDK API 43 | | 原理 | 序列化和反序列化过程需要大量的I/O操作 | 序列化和反序列化过程不需要大量的I/O操作 44 | | --- | 45 | | 开销 | 开销大 | 开销小 46 | | 效率 | 底 | 很高 47 | | 使用场景 | 序列化到本地或者通过网络传输 | 内存序列化 48 | 49 | ## 6. 性能优化时怎么做的 50 | 51 | ## 7. 如何控制进程的使用内存 52 | 53 | ## 8. http的数据结构 54 | 55 | ## 9. Android 和 JS的交互 56 | 57 | ## 10. 延时加载大图的方式 58 | 59 | ## 11. Token验证的方式 60 | 61 | ## 12. MediaPlay 播放音乐,连续切歌卡顿如何处理 62 | 63 | ## 13. Fragment 懒加载实现 64 | 65 | ## 14. 为什么 Android 规定不能在子线程中更新UI 66 | 67 | ## 15. Java 锁的使用方法 68 | 69 | ## 16. 对称加密和非对称加密的区别 70 | 71 | ## 17. 电商APP复杂首页怎么实现,都有什么方法 72 | 73 | ## 18. 如何避免OOM 74 | 75 | ## 19. Android 如何计算一个图片所占用的内存的 76 | 77 | ## 20. Bundel 机制说说明 78 | 79 | ## 21. RSA 生成的密钥使用的什么算法 80 | 81 | ## 22. 后台数据存储的用户信息是明文和还是加密的 82 | 83 | ## 23. 项目中哪些地方用到了多线程 84 | 85 | ## 24. Fragment 的栈维护 86 | 87 | ## 25. Activity 和 Fragment 的数据传递 88 | 89 | ## 26. 快速排序算法 90 | 91 | ## 27. 线程安全的问题遇到过哪些 92 | 93 | ## 28. 加入购物车的商品在未登录和登陆后的设计是怎样的,怎么合并数据 94 | 95 | ## 29. JNI的基础使用 96 | 97 | ## 30. adb 查看应用占用了多少内存的命令 98 | 99 | ## 31. https 传输的数据是否需要加密 100 | 101 | ## 32. APP启动白屏和黑屏的原因是什么 102 | 103 | ## 33. 二叉树特点 104 | 105 | ## 34. 栈集合和队列集合的区别 106 | -------------------------------------------------------------------------------- /article/RxJava-Operator-summary.md: -------------------------------------------------------------------------------- 1 | 1. create():创建一个完整的被观察者对象(Observable) 2 | 2. just():快速创建一个被观察者对象,并直接发送事件。最多只能发送10个参数。 3 | 3. fromArray():快速创建一个被观察者对象,并直接发送数组中的数据。会将数组中的数据转换为 Observable 对象。 4 | 4. fromIterable():快速创建一个被观察者对象,并直接发送集合中的数据。会将集合中的数据转换为 Observable 对象。 5 | 5. empty():快速创建一个被观察者对象,只调用 Complete 事件,直接通知完成。 6 | 6. error():快速创建一个被观察者对象,只调用 Error 事件,直接通知异常。可以自定义异常的类型。 7 | 7. never():快速创建一个被观察者对象,不发送任何事件。观察者接收后什么都不调用。 8 | 8. defer():有观察者订阅时,才会动态创建被观察者对象并且发送事件。 9 | 9. timer():快速创建一个被观察者对象,延迟指定时间后,发送一个数值0(Long 类型),即延迟指定时间后调用了Next(0)。它默认是在一个新的线程里面,也可以为其指定调度器。timer(long,TimeUnit,Scheduler) 10 | 10. interval():快速创建一个被观察者对象,每隔指定的时间就发送事件。发送事件的顺序是从0开始,无限递增1的整数序列,直到取消订阅时停止发送。它默认是在computation调度器上执行,也可以为其指定调度器,interval(long,TimeUnit,Scheduler)。 11 | 11. intervalRange():快速创建一个被观察者对象,每隔指定的时间发送一个事件,可以指定发送的数量。发送事件的顺序是从0开始,无限递增1的整数序列,直到达到指定的数量停止发送。 12 | 12. range():快速创建一个被观察者对象,从指定数值开始发送指定数量的事件。发送事件的顺序是从0开始,无限递增1的整数序列,可以从指定数值开始。它与 intervalRange()的区别是事件没有延迟发送,是连续发送的。 13 | 13. rangeLong():类似 range(), 区别在于该方法支持的类型是 Long。 14 | 14. map():被观察者发送的事件都通过指定的函数处理,转换为另一种事件,即被观察者发送的事件转换为任意的事件类型。 15 | 15. flatMap():将被观察者发送的事件拆分、转换,在合并成一个新的事件序列传递给观察者。新合并生成的事件序列是无序的 16 | 16. concatMap():类似 flatMap(),只是新的事件序列和旧的事件序列顺序是相同的。 17 | 17. buffer():定期从被观察者对象获取定量的事件放入到缓存区中最终发送。 18 | 18. concat():组合多个被观察者一起发送数据,合并后 按发送顺序串行执行。 19 | 19. concatArray():和 concat() 类似,区别在于 concat() 组合的被观察者数量<=4,concatArray() 组合的被观察者数>4。 20 | 20. merge():组合多个被观察者一起发送,合并后按照时间线并行执行。 21 | 21. mergeArray():和 merge() 类似,区别在于 merge() 足组合的被观察数量<=4,mergeArray() 组合的被观察者数量>4。 22 | 22. concatDelayError():在使用 concat() 时,若其中的一个被观察者发出 onError 事件后,则马上中断其他被观察者发送事件,使用 concatDelayError() 作用是,等所有的被观察者事件发送结束后触发 onError()。 23 | 23. mergeDelayError():在使用 merge() 时,若其中的一个被观察者发出 onError 事件后,则马上中断其他被观察者发送事件,使用 mergeDelayError() 作用是,等所有的被观察者事件发送结束后触发 onError()。 24 | 24. zip():合并多个被观察者发送的对象,生成一个新的事件序列(合并后的时间序列),并最终发送。事件的合并序列是按照原先的事件顺序,进行对位合并。最终合并的事件数量是多个被观察者中事件数量最少的数量。 25 | 25. combineLatest():当两个 Observables 中的任何一个发送了数据后,将先发送了数据的 Observables 的最新(最后)一个数据 与 另外一个 Observable 发送的每个数据结合,最终基于该函数的结果发送数据。 26 | 26. combineLatestDelayError():与 concatDelayError() / mergeDelayError() 类似。 27 | 27. reduce():把被观察者需要发送的事件聚合成1个事件在发送,聚合的逻辑根据需求撰写,但本质都是前2个数据聚合,然后与后1个数据继续进行聚合,依次类推。 28 | 28. collect():将被观察者 Observable 发送的数据事件收集到一个集合里。 29 | 29. startWith():在一个被观察者发送事件前,追加发送一个数据或一个新的被观察者。 30 | 30. startWithArray():在一个被观察者发送事件前,追加发送多个数据或多个新的被观察者。 31 | 31. count():统计被观察者发送事件的数量。 32 | 32. subscribe():订阅,连接观察者和被观察者。 33 | 33. delay():使被观察者延迟发送事件。 34 | 34. do():在某个时间的声明周期中调用。 35 | 35. onErrorReturn():被观察者发送事件的过程中发生错误,发送一个特殊事件正常终止发送。 36 | 36. onErrorResumeNext():遇到错误的时候发送一个新的 Observable。onErrorResumeNext()拦截的错误是 Throwable,若需拦截 Exception 请用 onExceptionResumeNext(),若 onErrorResumeNext() 拦截的错误是 Exception,则会将错误传递给观察者的 onError 方法。 37 | 37. onExceptionResumeNext():遇到错误的时候发送一个新的 Observable。onExceptionResumeNext()拦截的错误是 Exception,若需拦截 Throwable 请用 onErrorResumeNext(),若 onExceptionResumeNext() 拦截的错误是 Throwable,则会将错误传递给观察者的 onError() 方法。 38 | 38. retry():重试,当出现错误的时候,让被观察者重新发送事件。 39 | 39. retryUntil():出现错误的时候,判断是否需要重新发送数据,返回 true 表示不发送。 40 | 40. retryWhen():遇到错误时,将发生的错误传递给一个新的被观察者,并决定是否需要重新订阅原始被观察者去发送事件。 41 | 41. repeat():无条件地、重复发送 被观察者事件。 42 | 42. repeatWhen():无条件地、重复发送 被观察者事件。 43 | 43. subscribeOn():指定被观察者的操作线程。指定多次,只有第一次生效。 44 | 44. observeOn():指定观察者的操作线程。 45 | 45. filter():过滤特定条件的事件,如果 test() 方法返回 true 表示发送,返回 false 表示不发送。 46 | 46. ofType():过滤指定数据类型的事件。如果是指定的类型代表发送,否则不发送。 47 | 47. skip():跳过某个事件,skip(1) 表示跳过第一个事件,skip(1, TimeUnit.SECONDS) 表示跳过第 1s 发送的事件。 48 | 48. skipLast():跳过某个事件,skipLast(2) 跳过最后两个事件,skipLast(1, TimeUnit.SECONDS) 跳过最后 1s 发送的事件。 49 | 49. distinct():跳过事件序列中重复的事件。 50 | 50. distinctUntilChanged():跳过事件序列中连续重复的事件。 51 | 51. take():指定观察者最多接收的事件。 52 | 52. takeLast():指定观察者只接受最后相应个数的事件。 53 | 53. throttFirst():发送指定时间内发送的第一个事件。 54 | 54. throttLast():发送指定时间内发送的最后一个事件。 55 | 55. sample():发送指定时间内发送的最后一个事件。与throttleLast() 类似。 56 | 56. throttleWithTimeout():发送数据事件时,若2次发送事件的间隔<指定时间,就会丢弃前一次的数据,直到指定时间内都没有新数据发射时才会发送后一次的数据。 57 | 57. debounce():与throttleWithTimeout类似。 58 | 58. firstElement():选取事件队列中的第一个事件发送。 59 | 59. lastElement():选取事件队列中的最后一个事件发送。 60 | 60. elementAt():接收事件队列中指定索引的事件,索引从0开始,指定的最大索引可以大于事件队列的总数。 61 | 61. elementAtOrError():在 elementAt() 的基础上,当出现越界情况(即获取的位置索引 > 发送事件序列长度)时,即抛出异常。 62 | 62. all():判断发送的每个数据是否满足设置的条件,如果满足返回 true,否则返回 false。 63 | 63. takeWhile():判断发送的每个数据是否满足是指的条件,如果满足发送数据,否则不发送。 64 | 64. skipWhile():判断发送的每个数据是否满足是指的条件,直到判断返回 false,才开始发送之后的数据。 65 | 65. takeUntil():发送的数据与判断条件返回 true时,停止发送事件。 66 | 66. skipUntil():等到 skipUntil() 传入的 Observable 开始发送数据,(原始)第1个 Observable 的数据才开始发送数据。 67 | 67. SequenceEqual():判断两个 Observable 发送的数据是否相同,如果相同返回 true,否则返回 false。 68 | 68. contains():判断发送的数据中是否有指定的数据,包含返回 true,否则返回 false。 69 | 69. isEmpty():判断发送的数据是否为空,是返回 true,否则返回 false。 70 | 70. amb():当需要发送多个 Observable 时,只发送 先发送数据的 Observable 的数据,而其余 Observable 则被丢弃。 71 | 71. defaultIfEmpty():在不发送任何有效事件( Next 事件)、仅发送了 Complete 事件的前提下,发送一个默认值. 72 | 73 | **1~13 是创建操作符** 74 | 75 | **14~17 是转换操作符** 76 | 77 | **18~31 是合并操作符** 78 | 79 | **32~44 是功能性操作符** 80 | 81 | **45~61 是过滤操作符** 82 | 83 | **62~71 是条件操作符** -------------------------------------------------------------------------------- /utils/InsecureSHA1PRNGKeyDerivator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Stripped-down version of the SHA1PRNG provided by the Crypto provider. 3 | * 4 | * The Crypto provider that offers this functionality was deprecated on Android. 5 | * 6 | * Use this class only to retrieve encrypted data that couldn't be retrieved otherwise. 7 | */ 8 | class InsecureSHA1PRNGKeyDerivator { 9 | /** 10 | * Only public method. Derive a key from the given seed. 11 | * 12 | * Use this method only to retrieve encrypted data that couldn't be retrieved otherwise. 13 | * 14 | * @param seed seed used for the random generator, usually coming from a password 15 | * @param keySizeInBytes length of the array returned 16 | */ 17 | public static byte[] deriveInsecureKey(byte[] seed, int keySizeInBytes) { 18 | InsecureSHA1PRNGKeyDerivator derivator = new InsecureSHA1PRNGKeyDerivator(); 19 | derivator.setSeed(seed); 20 | byte[] key = new byte[keySizeInBytes]; 21 | derivator.nextBytes(key); 22 | return key; 23 | } 24 | // constants to use in expressions operating on bytes in int and long variables: 25 | // END_FLAGS - final bytes in words to append to message; 26 | // see "ch.5.1 Padding the Message, FIPS 180-2" 27 | // RIGHT1 - shifts to right for left half of long 28 | // RIGHT2 - shifts to right for right half of long 29 | // LEFT - shifts to left for bytes 30 | // MASK - mask to select counter's bytes after shift to right 31 | private static final int[] END_FLAGS = { 0x80000000, 0x800000, 0x8000, 0x80 }; 32 | private static final int[] RIGHT1 = { 0, 40, 48, 56 }; 33 | private static final int[] RIGHT2 = { 0, 8, 16, 24 }; 34 | private static final int[] LEFT = { 0, 24, 16, 8 }; 35 | private static final int[] MASK = { 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF, 36 | 0x000000FF }; 37 | // HASHBYTES_TO_USE defines # of bytes returned by "computeHash(byte[])" 38 | // to use to form byte array returning by the "nextBytes(byte[])" method 39 | // Note, that this implementation uses more bytes than it is defined 40 | // in the above specification. 41 | private static final int HASHBYTES_TO_USE = 20; 42 | // value of 16 defined in the "SECURE HASH STANDARD", FIPS PUB 180-2 43 | private static final int FRAME_LENGTH = 16; 44 | // miscellaneous constants defined in this implementation: 45 | // COUNTER_BASE - initial value to set to "counter" before computing "nextBytes(..)"; 46 | // note, that the exact value is not defined in STANDARD 47 | // HASHCOPY_OFFSET - offset for copy of current hash in "copies" array 48 | // EXTRAFRAME_OFFSET - offset for extra frame in "copies" array; 49 | // as the extra frame follows the current hash frame, 50 | // EXTRAFRAME_OFFSET is equal to length of current hash frame 51 | // FRAME_OFFSET - offset for frame in "copies" array 52 | // MAX_BYTES - maximum # of seed bytes processing which doesn't require extra frame 53 | // see (1) comments on usage of "seed" array below and 54 | // (2) comments in "engineNextBytes(byte[])" method 55 | // 56 | // UNDEFINED - three states of engine; initially its state is "UNDEFINED" 57 | // SET_SEED call to "engineSetSeed" sets up "SET_SEED" state, 58 | // NEXT_BYTES call to "engineNextByte" sets up "NEXT_BYTES" state 59 | private static final int COUNTER_BASE = 0; 60 | private static final int HASHCOPY_OFFSET = 0; 61 | private static final int EXTRAFRAME_OFFSET = 5; 62 | private static final int FRAME_OFFSET = 21; 63 | private static final int MAX_BYTES = 48; 64 | private static final int UNDEFINED = 0; 65 | private static final int SET_SEED = 1; 66 | private static final int NEXT_BYTES = 2; 67 | // Structure of "seed" array: 68 | // - 0-79 - words for computing hash 69 | // - 80 - unused 70 | // - 81 - # of seed bytes in current seed frame 71 | // - 82-86 - 5 words, current seed hash 72 | private transient int[] seed; 73 | // total length of seed bytes, including all processed 74 | private transient long seedLength; 75 | // Structure of "copies" array 76 | // - 0-4 - 5 words, copy of current seed hash 77 | // - 5-20 - extra 16 words frame; 78 | // is used if final padding exceeds 512-bit length 79 | // - 21-36 - 16 word frame to store a copy of remaining bytes 80 | private transient int[] copies; 81 | // ready "next" bytes; needed because words are returned 82 | private transient byte[] nextBytes; 83 | // index of used bytes in "nextBytes" array 84 | private transient int nextBIndex; 85 | // variable required according to "SECURE HASH STANDARD" 86 | private transient long counter; 87 | // contains int value corresponding to engine's current state 88 | private transient int state; 89 | /** 90 | * constant defined in "SECURE HASH STANDARD" 91 | */ 92 | private static final int H0 = 0x67452301; 93 | /** 94 | * constant defined in "SECURE HASH STANDARD" 95 | */ 96 | private static final int H1 = 0xEFCDAB89; 97 | /** 98 | * constant defined in "SECURE HASH STANDARD" 99 | */ 100 | private static final int H2 = 0x98BADCFE; 101 | /** 102 | * constant defined in "SECURE HASH STANDARD" 103 | */ 104 | private static final int H3 = 0x10325476; 105 | /** 106 | * constant defined in "SECURE HASH STANDARD" 107 | */ 108 | private static final int H4 = 0xC3D2E1F0; 109 | /** 110 | * offset in buffer to store number of bytes in 0-15 word frame 111 | */ 112 | private static final int BYTES_OFFSET = 81; 113 | /** 114 | * offset in buffer to store current hash value 115 | */ 116 | private static final int HASH_OFFSET = 82; 117 | /** 118 | * # of bytes in H0-H4 words;
119 | * in this implementation # is set to 20 (in general # varies from 1 to 20) 120 | */ 121 | private static final int DIGEST_LENGTH = 20; 122 | // The "seed" array is used to compute both "current seed hash" and "next bytes". 123 | // 124 | // As the "SHA1" algorithm computes a hash of entire seed by splitting it into 125 | // a number of the 512-bit length frames (512 bits = 64 bytes = 16 words), 126 | // "current seed hash" is a hash (5 words, 20 bytes) for all previous full frames; 127 | // remaining bytes are stored in the 0-15 word frame of the "seed" array. 128 | // 129 | // As for calculating "next bytes", 130 | // both remaining bytes and "current seed hash" are used, 131 | // to preserve the latter for following "setSeed(..)" commands, 132 | // the following technique is used: 133 | // - upon getting "nextBytes(byte[])" invoked, single or first in row, 134 | // which requires computing new hash, that is, 135 | // there is no more bytes remaining from previous "next bytes" computation, 136 | // remaining bytes are copied into the 21-36 word frame of the "copies" array; 137 | // - upon getting "setSeed(byte[])" invoked, single or first in row, 138 | // remaining bytes are copied back. 139 | private InsecureSHA1PRNGKeyDerivator() { 140 | seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET]; 141 | seed[HASH_OFFSET] = H0; 142 | seed[HASH_OFFSET + 1] = H1; 143 | seed[HASH_OFFSET + 2] = H2; 144 | seed[HASH_OFFSET + 3] = H3; 145 | seed[HASH_OFFSET + 4] = H4; 146 | seedLength = 0; 147 | copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET]; 148 | nextBytes = new byte[DIGEST_LENGTH]; 149 | nextBIndex = HASHBYTES_TO_USE; 150 | counter = COUNTER_BASE; 151 | state = UNDEFINED; 152 | } 153 | /* 154 | * The method invokes the SHA1Impl's "updateHash(..)" method 155 | * to update current seed frame and 156 | * to compute new intermediate hash value if the frame is full. 157 | * 158 | * After that it computes a length of whole seed. 159 | */ 160 | private void updateSeed(byte[] bytes) { 161 | // on call: "seed" contains current bytes and current hash; 162 | // on return: "seed" contains new current bytes and possibly new current hash 163 | // if after adding, seed bytes overfill its buffer 164 | updateHash(seed, bytes, 0, bytes.length - 1); 165 | seedLength += bytes.length; 166 | } 167 | /** 168 | * Changes current seed by supplementing a seed argument to the current seed, 169 | * if this already set; 170 | * the argument is used as first seed otherwise.
171 | * 172 | * The method overrides "engineSetSeed(byte[])" in class SecureRandomSpi. 173 | * 174 | * @param 175 | * seed - byte array 176 | * @throws 177 | * NullPointerException - if null is passed to the "seed" argument 178 | */ 179 | private void setSeed(byte[] seed) { 180 | if (seed == null) { 181 | throw new NullPointerException("seed == null"); 182 | } 183 | if (state == NEXT_BYTES) { // first setSeed after NextBytes; restoring hash 184 | System.arraycopy(copies, HASHCOPY_OFFSET, this.seed, HASH_OFFSET, 185 | EXTRAFRAME_OFFSET); 186 | } 187 | state = SET_SEED; 188 | if (seed.length != 0) { 189 | updateSeed(seed); 190 | } 191 | } 192 | /** 193 | * Writes random bytes into an array supplied. 194 | * Bits in a byte are from left to right.
195 | * 196 | * To generate random bytes, the "expansion of source bits" method is used, 197 | * that is, 198 | * the current seed with a 64-bit counter appended is used to compute new bits. 199 | * The counter is incremented by 1 for each 20-byte output.
200 | * 201 | * The method overrides engineNextBytes in class SecureRandomSpi. 202 | * 203 | * @param 204 | * bytes - byte array to be filled in with bytes 205 | * @throws 206 | * NullPointerException - if null is passed to the "bytes" argument 207 | */ 208 | protected synchronized void nextBytes(byte[] bytes) { 209 | int i, n; 210 | long bits; // number of bits required by Secure Hash Standard 211 | int nextByteToReturn; // index of ready bytes in "bytes" array 212 | int lastWord; // index of last word in frame containing bytes 213 | // This is a bug since words are 4 bytes. Android used to keep it this way for backward 214 | // compatibility. 215 | final int extrabytes = 7;// # of bytes to add in order to computer # of 8 byte words 216 | if (bytes == null) { 217 | throw new NullPointerException("bytes == null"); 218 | } 219 | // This is a bug since extraBytes == 7 instead of 3. Android used to keep it this way for 220 | // backward compatibility. 221 | lastWord = seed[BYTES_OFFSET] == 0 ? 0 222 | : (seed[BYTES_OFFSET] + extrabytes) >> 3 - 1; 223 | if (state == UNDEFINED) { 224 | throw new IllegalStateException("No seed supplied!"); 225 | } else if (state == SET_SEED) { 226 | System.arraycopy(seed, HASH_OFFSET, copies, HASHCOPY_OFFSET, 227 | EXTRAFRAME_OFFSET); 228 | // possible cases for 64-byte frame: 229 | // 230 | // seed bytes < 48 - remaining bytes are enough for all, 8 counter bytes, 231 | // 0x80, and 8 seedLength bytes; no extra frame required 232 | // 48 < seed bytes < 56 - remaining 9 bytes are for 0x80 and 8 counter bytes 233 | // extra frame contains only seedLength value at the end 234 | // seed bytes > 55 - extra frame contains both counter's bytes 235 | // at the beginning and seedLength value at the end; 236 | // note, that beginning extra bytes are not more than 8, 237 | // that is, only 2 extra words may be used 238 | // no need to set to "0" 3 words after "lastWord" and 239 | // more than two words behind frame 240 | for (i = lastWord + 3; i < FRAME_LENGTH + 2; i++) { 241 | seed[i] = 0; 242 | } 243 | bits = (seedLength << 3) + 64; // transforming # of bytes into # of bits 244 | // putting # of bits into two last words (14,15) of 16 word frame in 245 | // seed or copies array depending on total length after padding 246 | if (seed[BYTES_OFFSET] < MAX_BYTES) { 247 | seed[14] = (int) (bits >>> 32); 248 | seed[15] = (int) (bits & 0xFFFFFFFF); 249 | } else { 250 | copies[EXTRAFRAME_OFFSET + 14] = (int) (bits >>> 32); 251 | copies[EXTRAFRAME_OFFSET + 15] = (int) (bits & 0xFFFFFFFF); 252 | } 253 | nextBIndex = HASHBYTES_TO_USE; // skipping remaining random bits 254 | } 255 | state = NEXT_BYTES; 256 | if (bytes.length == 0) { 257 | return; 258 | } 259 | nextByteToReturn = 0; 260 | // possibly not all of HASHBYTES_TO_USE bytes were used previous time 261 | n = (HASHBYTES_TO_USE - nextBIndex) < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE 262 | - nextBIndex 263 | : bytes.length - nextByteToReturn; 264 | if (n > 0) { 265 | System.arraycopy(nextBytes, nextBIndex, bytes, nextByteToReturn, n); 266 | nextBIndex += n; 267 | nextByteToReturn += n; 268 | } 269 | if (nextByteToReturn >= bytes.length) { 270 | return; // return because "bytes[]" are filled in 271 | } 272 | n = seed[BYTES_OFFSET] & 0x03; 273 | for (;;) { 274 | if (n == 0) { 275 | seed[lastWord] = (int) (counter >>> 32); 276 | seed[lastWord + 1] = (int) (counter & 0xFFFFFFFF); 277 | seed[lastWord + 2] = END_FLAGS[0]; 278 | } else { 279 | seed[lastWord] |= (int) ((counter >>> RIGHT1[n]) & MASK[n]); 280 | seed[lastWord + 1] = (int) ((counter >>> RIGHT2[n]) & 0xFFFFFFFF); 281 | seed[lastWord + 2] = (int) ((counter << LEFT[n]) | END_FLAGS[n]); 282 | } 283 | if (seed[BYTES_OFFSET] > MAX_BYTES) { 284 | copies[EXTRAFRAME_OFFSET] = seed[FRAME_LENGTH]; 285 | copies[EXTRAFRAME_OFFSET + 1] = seed[FRAME_LENGTH + 1]; 286 | } 287 | computeHash(seed); 288 | if (seed[BYTES_OFFSET] > MAX_BYTES) { 289 | System.arraycopy(seed, 0, copies, FRAME_OFFSET, FRAME_LENGTH); 290 | System.arraycopy(copies, EXTRAFRAME_OFFSET, seed, 0, 291 | FRAME_LENGTH); 292 | computeHash(seed); 293 | System.arraycopy(copies, FRAME_OFFSET, seed, 0, FRAME_LENGTH); 294 | } 295 | counter++; 296 | int j = 0; 297 | for (i = 0; i < EXTRAFRAME_OFFSET; i++) { 298 | int k = seed[HASH_OFFSET + i]; 299 | nextBytes[j] = (byte) (k >>> 24); // getting first byte from left 300 | nextBytes[j + 1] = (byte) (k >>> 16); // getting second byte from left 301 | nextBytes[j + 2] = (byte) (k >>> 8); // getting third byte from left 302 | nextBytes[j + 3] = (byte) (k); // getting fourth byte from left 303 | j += 4; 304 | } 305 | nextBIndex = 0; 306 | j = HASHBYTES_TO_USE < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE 307 | : bytes.length - nextByteToReturn; 308 | if (j > 0) { 309 | System.arraycopy(nextBytes, 0, bytes, nextByteToReturn, j); 310 | nextByteToReturn += j; 311 | nextBIndex += j; 312 | } 313 | if (nextByteToReturn >= bytes.length) { 314 | break; 315 | } 316 | } 317 | } 318 | /** 319 | * The method generates a 160 bit hash value using 320 | * a 512 bit message stored in first 16 words of int[] array argument and 321 | * current hash value stored in five words, beginning OFFSET+1, of the array argument. 322 | * Computation is done according to SHA-1 algorithm. 323 | * 324 | * The resulting hash value replaces the previous hash value in the array; 325 | * original bits of the message are not preserved. 326 | * 327 | * No checks on argument supplied, that is, 328 | * a calling method is responsible for such checks. 329 | * In case of incorrect array passed to the method 330 | * either NPE or IndexOutOfBoundException gets thrown by JVM. 331 | * 332 | * @params 333 | * arrW - integer array; arrW.length >= (BYTES_OFFSET+6);
334 | * only first (BYTES_OFFSET+6) words are used 335 | */ 336 | private static void computeHash(int[] arrW) { 337 | int a = arrW[HASH_OFFSET ]; 338 | int b = arrW[HASH_OFFSET +1]; 339 | int c = arrW[HASH_OFFSET +2]; 340 | int d = arrW[HASH_OFFSET +3]; 341 | int e = arrW[HASH_OFFSET +4]; 342 | int temp; 343 | // In this implementation the "d. For t = 0 to 79 do" loop 344 | // is split into four loops. The following constants: 345 | // K = 5A827999 0 <= t <= 19 346 | // K = 6ED9EBA1 20 <= t <= 39 347 | // K = 8F1BBCDC 40 <= t <= 59 348 | // K = CA62C1D6 60 <= t <= 79 349 | // are hex literals in the loops. 350 | for ( int t = 16; t < 80 ; t++ ) { 351 | temp = arrW[t-3] ^ arrW[t-8] ^ arrW[t-14] ^ arrW[t-16]; 352 | arrW[t] = ( temp<<1 ) | ( temp>>>31 ); 353 | } 354 | for ( int t = 0 ; t < 20 ; t++ ) { 355 | temp = ( ( a<<5 ) | ( a>>>27 ) ) + 356 | ( ( b & c) | ((~b) & d) ) + 357 | ( e + arrW[t] + 0x5A827999 ) ; 358 | e = d; 359 | d = c; 360 | c = ( b<<30 ) | ( b>>>2 ) ; 361 | b = a; 362 | a = temp; 363 | } 364 | for ( int t = 20 ; t < 40 ; t++ ) { 365 | temp = ((( a<<5 ) | ( a>>>27 ))) + (b ^ c ^ d) + (e + arrW[t] + 0x6ED9EBA1) ; 366 | e = d; 367 | d = c; 368 | c = ( b<<30 ) | ( b>>>2 ) ; 369 | b = a; 370 | a = temp; 371 | } 372 | for ( int t = 40 ; t < 60 ; t++ ) { 373 | temp = (( a<<5 ) | ( a>>>27 )) + ((b & c) | (b & d) | (c & d)) + 374 | (e + arrW[t] + 0x8F1BBCDC) ; 375 | e = d; 376 | d = c; 377 | c = ( b<<30 ) | ( b>>>2 ) ; 378 | b = a; 379 | a = temp; 380 | } 381 | for ( int t = 60 ; t < 80 ; t++ ) { 382 | temp = ((( a<<5 ) | ( a>>>27 ))) + (b ^ c ^ d) + (e + arrW[t] + 0xCA62C1D6) ; 383 | e = d; 384 | d = c; 385 | c = ( b<<30 ) | ( b>>>2 ) ; 386 | b = a; 387 | a = temp; 388 | } 389 | arrW[HASH_OFFSET ] += a; 390 | arrW[HASH_OFFSET +1] += b; 391 | arrW[HASH_OFFSET +2] += c; 392 | arrW[HASH_OFFSET +3] += d; 393 | arrW[HASH_OFFSET +4] += e; 394 | } 395 | /** 396 | * The method appends new bytes to existing ones 397 | * within limit of a frame of 64 bytes (16 words). 398 | * 399 | * Once a length of accumulated bytes reaches the limit 400 | * the "computeHash(int[])" method is invoked on the array to compute updated hash, 401 | * and the number of bytes in the frame is set to 0. 402 | * Thus, after appending all bytes, the array contain only those bytes 403 | * that were not used in computing final hash value yet. 404 | * 405 | * No checks on arguments passed to the method, that is, 406 | * a calling method is responsible for such checks. 407 | * 408 | * @params 409 | * intArray - int array containing bytes to which to append; 410 | * intArray.length >= (BYTES_OFFSET+6) 411 | * @params 412 | * byteInput - array of bytes to use for the update 413 | * @params 414 | * from - the offset to start in the "byteInput" array 415 | * @params 416 | * to - a number of the last byte in the input array to use, 417 | * that is, for first byte "to"==0, for last byte "to"==input.length-1 418 | */ 419 | private static void updateHash(int[] intArray, byte[] byteInput, int fromByte, int toByte) { 420 | // As intArray contains a packed bytes 421 | // the buffer's index is in the intArray[BYTES_OFFSET] element 422 | int index = intArray[BYTES_OFFSET]; 423 | int i = fromByte; 424 | int maxWord; 425 | int nBytes; 426 | int wordIndex = index >>2; 427 | int byteIndex = index & 0x03; 428 | intArray[BYTES_OFFSET] = ( index + toByte - fromByte + 1 ) & 077 ; 429 | // In general case there are 3 stages : 430 | // - appending bytes to non-full word, 431 | // - writing 4 bytes into empty words, 432 | // - writing less than 4 bytes in last word 433 | if ( byteIndex != 0 ) { // appending bytes in non-full word (as if) 434 | for ( ; ( i <= toByte ) && ( byteIndex < 4 ) ; i++ ) { 435 | intArray[wordIndex] |= ( byteInput[i] & 0xFF ) << ((3 - byteIndex)<<3) ; 436 | byteIndex++; 437 | } 438 | if ( byteIndex == 4 ) { 439 | wordIndex++; 440 | if ( wordIndex == 16 ) { // intArray is full, computing hash 441 | computeHash(intArray); 442 | wordIndex = 0; 443 | } 444 | } 445 | if ( i > toByte ) { // all input bytes appended 446 | return ; 447 | } 448 | } 449 | // writing full words 450 | maxWord = (toByte - i + 1) >> 2; // # of remaining full words, may be "0" 451 | for ( int k = 0; k < maxWord ; k++ ) { 452 | intArray[wordIndex] = ( ((int) byteInput[i ] & 0xFF) <<24 ) | 453 | ( ((int) byteInput[i +1] & 0xFF) <<16 ) | 454 | ( ((int) byteInput[i +2] & 0xFF) <<8 ) | 455 | ( ((int) byteInput[i +3] & 0xFF) ) ; 456 | i += 4; 457 | wordIndex++; 458 | if ( wordIndex < 16 ) { // buffer is not full yet 459 | continue; 460 | } 461 | computeHash(intArray); // buffer is full, computing hash 462 | wordIndex = 0; 463 | } 464 | // writing last incomplete word 465 | // after writing free byte positions are set to "0"s 466 | nBytes = toByte - i +1; 467 | if ( nBytes != 0 ) { 468 | int w = ((int) byteInput[i] & 0xFF) <<24 ; 469 | if ( nBytes != 1 ) { 470 | w |= ((int) byteInput[i +1] & 0xFF) <<16 ; 471 | if ( nBytes != 2) { 472 | w |= ((int) byteInput[i +2] & 0xFF) <<8 ; 473 | } 474 | } 475 | intArray[wordIndex] = w; 476 | } 477 | return ; 478 | } 479 | } --------------------------------------------------------------------------------