├── Android ├── .DS_Store ├── Android 常见框架版本 三方库 开源库记录.md ├── Android 框架记录 三方库 开源库记录.md ├── Android入门 │ ├── 1. 四大组件 │ │ ├── Android 四大组件.md │ │ ├── Service 入门.md │ │ └── 四大启动模式 - Android 研发专栏 - CSDN 博客.md │ ├── 10. Resources │ │ ├── Android xml 资源文件中 @、@android_type、@_、?、@+ 含义和区别.md │ │ └── Android 根据资源名获取资源 ID - 技术小黑屋.md │ ├── 11. Retrofit + Okhttp │ │ ├── Android Retrofit 2.0 的详细 使用攻略(含实例讲解).md │ │ ├── Retrofit + RxJava + OkHttp 让网络请求变的简单 - 基础篇.md │ │ └── Retrofit + RxJava + OkHttp 让网络请求变的简单 - 封装篇.md │ ├── 12. RxJava │ │ ├── RxJava2 方法速查.md │ │ ├── RxJava原理.md │ │ ├── 一句话总结RxJava.md │ │ └── 扔物线_给 Android 开发者的 RxJava 详解.md │ ├── 13. Glide │ │ └── Android 图片加载框架最全解析(八),带你全面了解 Glide 4 的用法.md │ ├── 14. 注解框架 │ │ ├── Android Butter Knife 框架——最好用的 View 注入.md │ │ ├── Android Studio 中使用 Annotation Processor - 云在千峰.md │ │ └── Android 注解快速入门和实用解析.md │ ├── 15. Architecture components │ │ ├── Android Architecture Components 只看这一篇就够了.md │ │ ├── Android DataBinding 从入门到进阶.md │ │ ├── Architecture Components 全览 只看这一篇就够了.md │ │ ├── Lifecycle 原理解析.md │ │ ├── Lifecycle_ 生命周期组件详解 & 原理分析.md │ │ ├── LiveData 使用及原理解析.md │ │ ├── LiveData_ 观察者模式领域二三事.md │ │ ├── Navigation使用及源码解析.md │ │ ├── Paging:分页库的设计美学.md │ │ ├── ViewModel 使用及原理解析.md │ │ ├── ViewModel_ 从前世今生到追本溯源.md │ │ ├── 引入Component.md │ │ └── 迁移到AndroidX.md │ ├── 16. 代码管理 │ │ ├── Android UI 自动化测试在 RxImagePicker 中的实践历程.md │ │ ├── Android 单元测试只看这一篇就够了.md │ │ ├── Android 开发应该尝试的 UI 自动化测试.md │ │ └── Git 复习 2019年3月17日.md │ ├── 17. 性能优化 │ │ ├── APP启动优化.md │ │ ├── Android 内存泄露分析实战演练.md │ │ ├── Android 性能优化最佳实践.md │ │ ├── Android 视图优化策略.md │ │ └── JVM 初探:内存分配、GC 原理与垃圾收集器.md │ ├── 2. 布局和控件 │ │ ├── Android MotionLayout 相关 - 简书.md │ │ ├── ConstraintLayout 2.0 新特性详解及实战.md │ │ ├── ConstraintLayout.md │ │ └── xfhy ConstraintLayout 全解析.md │ ├── 3. 简单自定义View │ │ ├── 自定义 View 合集.md │ │ └── 自定义 View,有这一篇就够了.md │ ├── 4. 动画和手势 │ │ ├── Android 属性动画深入分析:让你成为动画牛人 - 任玉刚 - CSDN 博客.md │ │ ├── View 1-6:属性动画 Property Animation(上手篇).md │ │ ├── View 动画和属性动画(1).md │ │ ├── View 动画和属性动画.md │ │ ├── View 进阶 - 手势检测 (GestureDetector).md │ │ ├── View 进阶 - 缩放手势检测 (ScaleGestureDecetor).md │ │ ├── layoutAnimation 视图动画.md │ │ └── 动画知识脑图.mindmap │ ├── 5. 网络 │ │ └── HTTP 必知必会的那些.md │ ├── 6. 图片加载 │ │ ├── Android DiskLruCache 完全解析,硬盘缓存的最佳方案.md │ │ ├── Android drawable 微技巧,你所不知道的 drawable 的那些细节.md │ │ ├── Android 中 Bitmap 内存优化.md │ │ ├── Android 高效加载大图、多图解决方案,有效避免程序 OOM.md │ │ ├── Bitmap工具类.md │ │ └── tudo.md │ ├── 7. 文件和数据库 │ │ ├── Java 序列化的高级认识.md │ │ ├── Java 文件流总结.md │ │ └── 借助 Stetho 在 Chrome 上调试 Android 网络 & 数据库.md │ └── 9. 异步线程池 │ │ ├── Handler全解析.md │ │ ├── Java 线程同步:synchronized 锁住的是代码还是对象.md │ │ ├── ThreadPoolUtil.java │ │ ├── java 中的 wait、notify、notifyAll.md │ │ └── 初始 线程和线程池.md ├── Android学习笔记 │ ├── Android 内存泄露分析实战演练.md │ ├── Android 动画.md │ ├── Android 数据库.md │ ├── Fragment 碎片.md │ ├── JNI.md │ ├── ListView.md │ ├── SVN 版本控制.md │ ├── 公司的一些习惯.md │ ├── 多媒体.md │ ├── 杂乱的知识点 │ │ ├── AIDL简单使用.md │ │ ├── AOP面向切面编程.md │ │ ├── APP登录 技术点与流程全解.md │ │ ├── Activity向Fragment传值 大坑.md │ │ ├── Activity生命周期.md │ │ ├── Android DecorView浅析.md │ │ ├── Android View的点击事件无效.md │ │ ├── Android 动画 (2).md │ │ ├── Android 启动模式.md │ │ ├── Android 多击事件.md │ │ ├── Android 强、软、弱、虚引用 区别和使用场景.md │ │ ├── Android 性能微型优化建议.md │ │ ├── Android 未root查看ANR异常.md │ │ ├── Android 桌面小控件.md │ │ ├── Android上使用Vector 矢量图片.md │ │ ├── Android之ContentObserver内容观察者的使用.md │ │ ├── Android平台架构.md │ │ ├── Android平台架构.png │ │ ├── Android系统自带的常用数据库.md │ │ ├── App异常处理.md │ │ ├── Bundle.md │ │ ├── CheckBox代码去掉小方框.md │ │ ├── DialogFragment全屏.md │ │ ├── DialogFragment遇到的坑.md │ │ ├── Handler 总结.md │ │ ├── JSON解析.md │ │ ├── Kotlin和RecyclerView的一个demo.md │ │ ├── Kotlin配合Gson进行json数据解析.md │ │ ├── MVP初识.md │ │ ├── Notification通知.md │ │ ├── RxJava2操作符.png │ │ ├── Viewpager中的Fragment的生命周期.md │ │ ├── fragment生命周期.md │ │ ├── xutils3基本使用.md │ │ ├── 一些杂乱的知识点(一).md │ │ ├── 一些杂乱的知识点(三).md │ │ ├── 一些杂乱的知识点(二).md │ │ ├── 使用GSON解析json数据.md │ │ ├── 使用Kotlin配合RxJava网络请求.md │ │ ├── 使用LitePal操作数据库.md │ │ ├── 使用OkHttp3遇到的一些坑.md │ │ ├── 全屏.md │ │ ├── 切换全屏,取消全屏.md │ │ ├── 利用Android Support Library注解帮你发现潜在的问题.md │ │ ├── 加密.md │ │ ├── 华为手机无法打印日志解决办法.md │ │ ├── 单例模式.md │ │ ├── 单元测试.md │ │ ├── 双击返回键退出.md │ │ ├── 回调编写.md │ │ ├── 在组件中获取Application.md │ │ ├── 封装一个万能的PopupWindow.md │ │ ├── 屏幕高度+状态栏高度.md │ │ ├── 常见布局.md │ │ ├── 底部栏 布局.md │ │ ├── 强制让字体不随着系统字体大小而变化.md │ │ ├── 热修复原理.png │ │ ├── 生成快捷方式.md │ │ ├── 电话状态的监听.md │ │ ├── 监测Activity的生命周期事件.md │ │ ├── 组件化开发注意事项.md │ │ ├── 给Android开发者的RxJava详解.md │ │ ├── 网络缓存.md │ │ ├── 自定义控件 带删除按钮的EditText.md │ │ ├── 获取系统内存信息.md │ │ ├── 解决Android Studio配置完Kotlin下载慢的问题.md │ │ └── 锁屏事件监听.md │ ├── 第一天 adb,快捷键,布局.md │ ├── 第二天 sd卡,SharedPreferences,xml.md │ ├── 第五天 网络.md │ ├── 第四天 网络.md │ ├── 网络完整笔记.md │ ├── 自定义控件 实战.md │ └── 面试.md ├── Android常用优秀开源框架(一).md ├── Android高级 │ ├── .DS_Store │ ├── 1. Binder、AIDL、多进程 │ │ ├── Android Bander 设计与实现.md │ │ ├── Android IPC机制 脑图.md │ │ ├── Android IPC机制.md │ │ ├── Android 跨进程通信:图文详解 Binder 机制 原理.md │ │ ├── Binder核心原理.md │ │ ├── 写给 Android 应用工程师的 Binder 原理剖析.md │ │ └── 自己的笔记_Android AIDL 跨进程通信.md │ ├── 1. IPC机制 │ │ ├── Android Bander 设计与实现.md │ │ ├── Android IPC机制 脑图.md │ │ ├── Android IPC机制.md │ │ ├── Android 跨进程通信:图文详解 Binder 机制 原理.md │ │ ├── Binder核心原理.md │ │ ├── 写给 Android 应用工程师的 Binder 原理剖析.md │ │ └── 自己的笔记_Android AIDL 跨进程通信.md │ ├── 10. 理解Window和WindowManager │ │ └── Activity、Window、View 三者关系.md │ ├── 11. 刁钻问题汇总 │ │ ├── Android 中为什么主线程不会因为 Looper.loop() 里的死循环卡死?.md │ │ ├── Android 中子线程真的不能更新 UI 吗.md │ │ └── 把玩Android多进程.pdf.pdf │ ├── 12. OkHttp+Retrofit │ │ ├── OKHttp 源码解析.md │ │ ├── OkHttp3 原理探究 by xfhy.md │ │ ├── Okhttp3 基本使用.md │ │ ├── Retrofit 原理解析 by xfhy.md │ │ ├── Retrofit 原理解析最简洁的思路.md │ │ └── Retrofit 是如何工作的?.md │ ├── 13. RxJava │ │ ├── RxJava2 方法速查.md │ │ ├── RxJava解析 基本订阅流程+线程切换 by xfhy.md │ │ ├── 一句话总结RxJava.md │ │ ├── 友好 RxJava2.x 源码解析(一)基本订阅流程.md │ │ ├── 友好 RxJava2.x 源码解析(三)zip 源码分析.md │ │ ├── 友好 RxJava2.x 源码解析(二)线程切换.md │ │ ├── 给 Android 开发者的 RxJava 详解.md │ │ └── 详解 RxJava 的消息订阅和线程切换原理.md │ ├── 14. Glide │ │ ├── Android 图片加载框架最全解析(三),深入探究 Glide 的缓存机制 - 郭霖的专栏 - CSDN 博客.md │ │ ├── Android 图片加载框架最全解析(二),从源码的角度理解 Glide 的执行流程 - 郭霖的专栏 - CSDN 博客.md │ │ ├── xfhy Glide(一)主流程源码解析.md │ │ ├── xfhy Glide(二)缓存机制探索.md │ │ └── 面试官:简历上最好不要写 Glide,不是问源码那么简单.md │ ├── 15. Groovy基础 │ │ ├── Gradle 从入门到实战 - Groovy 基础 - 任玉刚 - CSDN 博客.md │ │ └── xfhy Groovy 基础.md │ ├── 16. Gradle 插件基础 │ │ ├── Gradle系列(三) Gradle配置构建和渠道包.md │ │ ├── Gradle系列(二) Gradle执行顺序和task.md │ │ ├── Gradle系列(四) Gradle插件.md │ │ ├── 一篇文章带你了解 Gradle 插件的所有创建方式.md │ │ ├── 全面理解 Gradle - 执行时序 - 任玉刚 - CSDN 博客.md │ │ └── 写给 Android 开发者的 Gradle 系列(三)撰写 plugin.md │ ├── 2. View 的绘制 │ │ ├── Android View 的工作流程 - 凶残的程序员.md │ │ ├── Android Window 机制探索 - 凶残的程序员.md │ │ ├── Android 视图状态及重绘流程分析,带你一步步深入了解 View(三).md │ │ ├── Android 视图绘制流程完全解析,带你一步步深入了解 View(二).md │ │ ├── LayoutInflater 原理分析,带你一步步深入了解 View(一).md │ │ ├── ListView 工作原理完全解析,带你从源码的角度彻底理解.md │ │ ├── Window 与 PhoneWindow 入门.md │ │ ├── 图解 View 测量、布局及绘制原理.md │ │ ├── 布局渲染 inflate 方法的前世今生.md │ │ ├── 死磕Android_View工作原理你需要知道的一切.md │ │ └── 看书笔记_View的工作原理.md │ ├── 20. jni │ │ ├── Android JNI 学习 (二)——实战 JNI 之 “hello world” - 简书.md │ │ ├── Android JNI 学习 (四)——JNI 的常用方法的中文 API.md │ │ ├── Android JNI(一)——NDK 与 JNI 基础 - 简书.md │ │ ├── NDK学习资料.md │ │ └── 纸上浅谈 │ │ │ ├── 1 Android JNI 基础知识.md │ │ │ ├── 2 Android 通过 JNI 访问 Java 字段和方法调用.md │ │ │ └── 3 Android JNI 数组操作.md │ ├── 3. View的事件体系 │ │ ├── Android 事件分发机制详解:史上最全面、最易懂.md │ │ └── View的基础知识.md │ ├── 4. 消息队列 │ │ ├── Handler 全家桶之 —— Handler 源码解析.md │ │ └── Handler机制你需要知道的一切.md │ ├── 5. Activity 难点 │ │ ├── 3 分钟看懂 Activity 启动流程背景介绍一张图明白 Activity 的启动流程总结参考链接.md │ │ ├── Activity的生命周期和启动模式.md │ │ ├── intent-filter 匹配规则.md │ │ ├── onSaveInstanceState() 和 onRestoreInstanceState() 使用详解.md │ │ ├── setResult() 的调用时机.md │ │ ├── 关于 onConfigurationChanged 方法及常见问题解决.md │ │ ├── 原来一个 App 是这样启动起来的,一看就懂.md │ │ └── 死磕Android_App 启动过程(含 Activity 启动过程).md │ ├── 6. Service 难点 │ │ ├── Android 中 startService 和 bindService 的区别.md │ │ ├── Service知识点.md │ │ ├── 死磕Android_Service启动流程分析(一).md │ │ └── 死磕Android_Service绑定流程分析(二).md │ ├── 7. BroadCastReceiver │ │ ├── android 静态广播和动态广播的区别和用法.md │ │ ├── 广播的一些基本操作.md │ │ └── 死磕Android_BroadcastReceiver 工作过程.md │ ├── 8. ContentProvider │ │ ├── ContentProvider 方法运行线程.md │ │ ├── android ContentProvider onCreate() 在 Application onCreate() 之前执行.md │ │ └── 死磕Android_ContentProvider 启动.md │ ├── 9. AsyncTask │ │ └── Android 源码分析—带你认识不一样的 AsyncTask.md │ ├── RecyclerView │ │ ├── Android RecyclerView入门_张鸿洋.md │ │ ├── RecyclerView 使用.md │ │ ├── RecyclerView 常用小技巧.md │ │ ├── RecyclerView 库中被我们忽略的部分.md │ │ ├── RecyclerView 梳理:点击 & 长按事件、分割线、拖曳排序、滑动删除.md │ │ └── RecyclerView和ScrollView的滑动冲突.md │ └── 组件化 │ │ └── 基你太美 │ │ ├── utf-8' '0. AucFrame 之简介及学习.pdf.pdf │ │ ├── utf-8' '1. AucFrame 之让你的 Gradle 更智能.pdf.pdf │ │ ├── utf-8' '2. AucFrame 之统一管理 Gradle.pdf.pdf │ │ ├── utf-8' 'AucFrame.pdf.pdf │ │ └── 基你太美 密码.md ├── Gradle │ ├── Gradle 妙用,统一化自动依赖管理.md │ ├── Gradle 自定义插件以及发布方法.md │ ├── 一个项目如何编译多个不同签名、包名、资源等,的 apk?.md │ ├── 刘望舒_写给 Android 开发的 Gradle 知识体系.md │ ├── 看完这篇 Gradle,你才能去面腾讯.md │ ├── 这一次彻底弄明白 Gradle 相关配置.md │ └── 这样使用 Gradle 可以神奇地打各种渠道包.md ├── JNI │ ├── 1. NDK和JNI基本概念.md │ ├── 2. Android JNI初识 HelloWorld.md │ └── 3. JNI开发系列之Java与C相互调用.md ├── Material Design │ ├── 12个MD控件.md │ ├── AppbarLayout 的简单用法.md │ ├── Bottom Sheets–底部动作条.md │ ├── BottomsheetDialogFragment.md │ ├── Chips.md │ ├── DrawerLayout 和 NavigationView 使用详解.md │ ├── FloatingActionButton的滚动隐藏和显示.md │ ├── Material Design 控件常用的属性.md │ ├── Material Design(一).md │ ├── Material Design(二).md │ ├── Material Design.md │ ├── Snackbar 使用详解.md │ └── TextInputLayout、TextInputEditText.md ├── RecyclerView │ ├── RecyclerView item点击水波纹效果.md │ ├── RecyclerView 官方分割线.md │ ├── RecyclerView 更强大的滚动控件.md │ ├── RecyclerView万能分组 │ │ ├── ComplexListLayout │ │ │ ├── .gitignore │ │ │ ├── .idea │ │ │ │ ├── compiler.xml │ │ │ │ ├── copyright │ │ │ │ │ └── profiles_settings.xml │ │ │ │ ├── gradle.xml │ │ │ │ ├── misc.xml │ │ │ │ ├── modules.xml │ │ │ │ └── runConfigurations.xml │ │ │ ├── app │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src │ │ │ │ │ ├── androidTest │ │ │ │ │ └── java │ │ │ │ │ │ └── com │ │ │ │ │ │ └── feiyang │ │ │ │ │ │ └── complexlistlayout │ │ │ │ │ │ └── ExampleInstrumentedTest.java │ │ │ │ │ ├── main │ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ │ ├── java │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── feiyang │ │ │ │ │ │ │ └── complexlistlayout │ │ │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ │ │ ├── TestAdapter.java │ │ │ │ │ │ │ ├── adapter │ │ │ │ │ │ │ ├── SectionedRecyclerViewAdapter.java │ │ │ │ │ │ │ └── SectionedSpanSizeLookup.java │ │ │ │ │ │ │ ├── entity │ │ │ │ │ │ │ └── TestEntity.java │ │ │ │ │ │ │ ├── holder │ │ │ │ │ │ │ ├── EmptyViewHolder.java │ │ │ │ │ │ │ ├── FooterHolder.java │ │ │ │ │ │ │ ├── TestSectionBodyHolder.java │ │ │ │ │ │ │ ├── TestSectionFooterHolder.java │ │ │ │ │ │ │ ├── TestSectionHeaderHolder.java │ │ │ │ │ │ │ └── TypeAbstractViewHolder.java │ │ │ │ │ │ │ ├── listener │ │ │ │ │ │ │ ├── LoadMoreListener.java │ │ │ │ │ │ │ └── RecycleViewScrollHelper.java │ │ │ │ │ │ │ ├── util │ │ │ │ │ │ │ ├── DatasUtil.java │ │ │ │ │ │ │ └── DeviceInforUtils.java │ │ │ │ │ │ │ └── widgets │ │ │ │ │ │ │ └── SectionedGridDivider.java │ │ │ │ │ └── res │ │ │ │ │ │ ├── layout │ │ │ │ │ │ ├── activity_main.xml │ │ │ │ │ │ ├── item_section_body.xml │ │ │ │ │ │ ├── item_section_footer.xml │ │ │ │ │ │ ├── item_section_header.xml │ │ │ │ │ │ └── layout_footer.xml │ │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── values-w820dp │ │ │ │ │ │ └── dimens.xml │ │ │ │ │ │ └── values │ │ │ │ │ │ ├── colors.xml │ │ │ │ │ │ ├── dimens.xml │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── test │ │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── feiyang │ │ │ │ │ └── complexlistlayout │ │ │ │ │ └── ExampleUnitTest.java │ │ │ ├── build.gradle │ │ │ ├── gradle.properties │ │ │ ├── gradle │ │ │ │ └── wrapper │ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ └── settings.gradle │ │ ├── SectionedRecyclerViewAdapter.java │ │ ├── TestAdapter.java │ │ └── 使用方法.md │ ├── RecyclerView分组.md │ ├── RecyclerView分组的伸缩栏.md │ ├── RecyclerView禁止滚动.md │ └── 去除RecyclerView滑动边缘阴影效果.md ├── flutter │ ├── 1. Flutter 安装和初体验.md │ ├── 2. Flutter 学习指南:编写第一个应用.md │ ├── 3. Flutter 学习指南:熟悉 Dart 语言.md │ ├── 4. Flutter 学习指南:UI 布局和控件.md │ ├── 5. Flutter 学习指南:交互、手势和动画.md │ ├── 6. Flutter IO 相关的基础知识.md │ └── 7. 封装 API 插件.md ├── kotlin │ ├── Java与Kotlin兼容问题.md │ ├── Kotlin中的类.md │ ├── Kotlin关键字与操作符.md │ ├── Kotlin学习tips.md │ ├── Kotlin小知识点.md │ ├── Kotlin的扩展库.md │ ├── Kotlin相比Java 7的优势.md │ ├── kotlin 在Android中的应用实践.md │ ├── kotlin与Java互操作.md │ ├── 加快kotlin编译速度.md │ ├── 常用扩展.md │ ├── 扔物线教程(码上开学) │ │ ├── 1 Kotlin 的变量、函数和类型.md │ │ └── xfhy_协程理解.md │ └── 让你的 Kotlin 代码远离 !!.md ├── other │ ├── .DS_Store │ ├── Android 8.1调研.md │ ├── Android O(8.0)新功能预览.md │ ├── Android Studio使用.md │ ├── Android Studio返回上一光标处失效.md │ ├── Android Studio项目 目录含义.md │ ├── Android 中需要掌握的高级技巧.md │ ├── Android 五子棋开发经验.md │ ├── Android 使用网络技术 (第一行代码).md │ ├── Android 保活措施.md │ ├── Android 反编译基础.md │ ├── Android 后台运行白名单,优雅实现保活.md │ ├── Android 无障碍辅助功能基础.md │ ├── Android 编程规范.md │ ├── Android 运行时权限.md │ ├── AndroidKiller 使用与配置.md │ ├── Android体系与系统架构.md │ ├── Android免root查看数据库内容.md │ ├── Android性能优化来龙去脉总结.md │ ├── Android版本号 API对应表.md │ ├── C语言基础知识.md │ ├── 修改.aar后重新打包.md │ ├── 实现圆形图片的一种骚方式.md │ ├── 屏幕适配 │ │ ├── AndroidAutoSize 原理 今日头条屏幕适配方案终极版正式发布!.md │ │ ├── SmallestWidth 限定符适配方案.md │ │ ├── dpi 、 dip 、分辨率、屏幕尺寸、px、density 关系以及换算.md │ │ ├── 今日头条-一种极低成本的 Android 屏幕适配方式.md │ │ └── 今日头条适配方案1.md │ ├── 框架记录.md │ └── 自定义控件 │ │ ├── Android控件架构与自定义控件详解.md │ │ ├── 仿华为手机管家的病毒扫描 Android自定义View.md │ │ ├── 学自定义控件看hencoder就好了 │ │ ├── 自定义AlertDialog.md │ │ ├── 自定义TextView 可展开收缩.md │ │ ├── 自定义Toast显示(不限时+在其他应用之上显示).md │ │ ├── 自定义View 让文字居中画出来.md │ │ ├── 自定义View.md │ │ └── 自定义密码 输入界面.md ├── 书籍笔记 │ ├── Android进阶之光 │ │ ├── Behavior.md │ │ ├── HTTP协议原理.md │ │ └── View.md │ └── 安卓开发艺术探索 │ │ ├── Android中的IPC方式.md │ │ ├── Binder.md │ │ └── Serializable和Parcelable.md ├── 他人源码阅读笔记 │ └── KotlinMvp 小视频播放 │ │ ├── Retrofit+RxJava2.md │ │ ├── fragment 懒加载.md │ │ ├── kotlin fragment切换技巧.md │ │ ├── kotlin搭建MVP.md │ │ └── 将扩展函数统一放到一个文件中.md ├── 四大组件 │ ├── Activity.md │ ├── Activity启动流程全解析.md │ ├── BroadcastReceiver广播接收者.md │ ├── ContentProvider 内容提供者.md │ └── Service 服务.md ├── 性能优化 │ └── 面试官:今日头条启动很快,你觉得可能是做了哪些优化?.md ├── 杂乱知识点 │ ├── Android 内存泄露分析实战演练.md │ ├── Android快捷方式-Shortcuts.md │ ├── DialogFragment全屏.md │ └── Listview 中的 item 每个 addTextChangedListener 都被触发了.md ├── 源码解析 │ ├── Android-skin-support换肤原理详解.md │ ├── ButterKnife │ │ └── ButterKnife 原理解析.md │ ├── Handler源码理解.md │ ├── OkHttp3源码分析.md │ ├── Retrofit │ │ ├── Retrofit与动态代理.md │ │ ├── Retrofit基本使用.md │ │ └── Retrofit源码解析.md │ ├── View事件分发机制.md │ ├── 死磕Android_AOSP编译过程.md │ └── 热更新 │ │ ├── Android dex分包方案.md │ │ ├── Android 热补丁动态修复框架小结.md │ │ ├── tinker原理.md │ │ └── 安卓App热补丁动态修复技术介绍-QQ空间方案.md ├── 第三方库的使用 │ ├── Bugly.md │ └── Glide使用.md ├── 自定义View │ ├── 3-1 触摸反馈,以及 HenCoder Plus.md │ ├── UI 部分 2-1 布局基础.md │ ├── UI 部分 2-2 全新定义 View 的尺寸.md │ ├── UI 部分 2-3 定制 Layout 的内部布局.md │ ├── 自定义 View 1-1 绘制基础.md │ ├── 自定义 View 1-2 Paint 详解.md │ ├── 自定义 View 1-3 drawText() 文字的绘制.md │ ├── 自定义 View 1-4 Canvas 对绘制的辅助 clipXXX() 和 Matrix.md │ ├── 自定义 View 1-5 绘制顺序.md │ ├── 自定义 View 1-6:属性动画 Property Animation(上手篇).md │ ├── 自定义 View 1-7:属性动画 Property Animation(进阶篇).md │ └── 自定义 View 1-8 硬件加速.md ├── 适配 │ ├── Android P │ │ ├── Android 9.0加密问题适配.md │ │ ├── Android 9.0限制明文流量的网络请求.md │ │ ├── Android P 上的提醒弹窗 (Android P调用私有API etected problems with API compatibility(v.md │ │ ├── Android P 刘海屏适配全攻略.md │ │ └── getMainThreadHandler() 被hide.md │ ├── Android Q │ │ ├── Android Q 要来了,给你一份很全面的适配指南.md │ │ ├── Android Q 适配指北_by xfhy.md │ │ ├── Android Q 适配指南 让你少走一堆弯路.md │ │ ├── veridex 使用教程_扫描非法API调用.md │ │ └── 后台启动Activity适配.md │ ├── android 7.0 │ │ └── android7.0 调用相机的坑.md │ ├── android 8.0 │ │ ├── Android 8.0开启后台Service适配.md │ │ ├── Android 8.0系统的通知栏适配.md │ │ ├── Android 8.0行为变更_隐式广播限制.md │ │ └── Android8.0时代的后台任务JetPack-WorkManager详解.md │ ├── 各系统新特性 │ │ ├── Andrid 7.0 新特性.md │ │ ├── Android 10 系统新特性解读.md │ │ ├── Android 5.0 新特性.md │ │ ├── Android 6.0 新特性.md │ │ ├── Android 8.0 新特性.md │ │ └── Android P 版本 (9.0) 新功能介绍和兼容性处理.md │ └── 屏幕 │ │ ├── Android 开发中的各种单位.md │ │ ├── 今日头条屏幕适配方案终极版正式发布!.md │ │ ├── 屏幕适配工具类.md │ │ ├── 屏幕适配问题汇总及解决.md │ │ └── 骚年你的屏幕适配方式该升级了!- 今日头条适配方案.md └── 音视频 │ └── 国内外优秀音视频博客.md ├── Git ├── Git学习.md ├── Git工作流程.md ├── git 2019.9.9复习.md ├── git 复习 2019年3月17日.md └── 总结将代码托管到GitHub上.md ├── Linux ├── Linux GDB使用日常.md ├── Linux 使用日常.md ├── Linux 程序设计入门.md ├── Ubantu │ ├── Linux基本命令.md │ ├── Linux笔记 │ │ ├── Linux GDB使用日常.md │ │ ├── Linux 使用日常.md │ │ └── Linux 程序设计入门.md │ ├── vim基本操作.md │ ├── 在Ubuntu搭建安卓开发环境.md │ ├── 安装Linux.md │ └── 简单使用ubantu.md └── 科学上网.md ├── README.md ├── java ├── .DS_Store ├── HashSet和TreeSet的区别.md ├── Java JDBC.md ├── Java String学习笔记.md ├── Java 多态.md ├── Java 异常.md ├── Java 接口.md ├── Java 文件操作.md ├── Java 类.md ├── Java 集合(续).md ├── Java 集合.md ├── Java基础.md ├── Java核心知识点 │ ├── 1. 谈谈你对Java平台的理解.md │ ├── 第11讲 java提供了哪些io方式? nio如何实现多路复用?.md │ ├── 第12讲 java有几种文件拷贝方式?哪一种最高效?.md │ ├── 第13讲 谈谈接口和抽象类有什么区别?.md │ ├── 第14讲 谈谈你知道的设计模式?.md │ ├── 第15讲 synchronized和ReentrantLock有什么区别呢?.md │ ├── 第16讲 synchronized底层如何实现?什么是锁的升级、降级?.md │ ├── 第17讲 一个线程两次调用start()方法会出现什么情况?.md │ ├── 第18讲 什么情况下Java程序会产生死锁?如何定位、修复?.md │ ├── 第19讲 Java并发包提供了哪些并发工具类?.md │ ├── 第20讲 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?.md │ ├── 第21讲 Java并发类库提供的线程池有哪几种? 分别有什么特点?.md │ ├── 第23讲 请介绍类加载过程,什么是双亲委派模型?.md │ ├── 第24讲 有哪些方法可以在运行时动态生成一个Java类?.md │ ├── 第25讲 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError.md │ ├── 第2讲 Exception和Error有什么区别.md │ ├── 第3讲 谈谈final、finally、 finalize有什么不同.md │ ├── 第4讲 强引用、软引用、弱引用、幻象引用有什么区别.md │ ├── 第5讲 string、stringbuffer、stringbuilder有什么区别.md │ ├── 第6讲 动态代理是基于什么原理?.md │ ├── 第7讲 int和Integer有什么区别?.md │ ├── 第8讲 对比Vector、ArrayList、LinkedList有何区别?.md │ └── 第9讲 对比Hashtable、HashMap、TreeMap有什么不同?.md ├── Java的反射机制.md ├── Java虚拟机 │ ├── 01 Java代码是怎么运行的?.md │ ├── 02 Java的基本类型.md │ └── 03 Java虚拟机是如何加载Java类的.md ├── wamp初识,java jdbc连接mysql数据库.md ├── 别再说你不懂线程池-做个优雅的攻城狮.md ├── 反射详解.md ├── 基础知识 │ ├── 注解学习.md │ └── 浅析Java的深拷贝和浅拷贝.md ├── 接口和抽象类区别.md └── 源码解读 │ ├── ArrayList.md │ ├── HashMap源码解析(JDK8).md │ ├── LinkedHashMap源码解析(JDK8).md │ ├── LinkedList.md │ ├── SparseArray源码解析.md │ └── 从源码角度彻底搞懂String,StringBuffer,StringBuilder.md ├── 操作系统 ├── README.md ├── 内存管理.md ├── 操作系统概述.md ├── 文件管理.md ├── 死锁.md ├── 计算机操作系统-概述.md ├── 计算机操作系统-进程管理.md ├── 进程与线程.md └── 进程管理.md ├── 数据结构与算法 ├── README.md ├── 常用数据结构与算法及学习技巧.md ├── 归并排序和快速排序.md ├── 排序 │ ├── 冒泡排序.cpp │ ├── 合并排序(归并排序).cpp │ ├── 常见排序算法.md │ ├── 快速排序.cpp │ ├── 插入排序.cpp │ ├── 桶排序.cpp │ └── 计数排序.cpp └── 桶排序,计数排序,基数排序.md └── 计算机网络 ├── HTTP和HTTPS.md ├── IP.md ├── README.md ├── TCP三次握手与四次分手.md ├── TCP和UDP的区别.md ├── 计算机网络体系结构.md └── 趣谈网络协议 ├── 应用层 ├── 第14讲 HTTP协议:看个新闻原来这么麻烦.md ├── 第15讲 HTTPS协议:点外卖的过程原来这么复杂.md ├── 第16讲 流媒体协议:如何在直播里看到美女帅哥?.md ├── 第17讲 P2P协议:我下小电影,99%急死你.md ├── 第18讲 DNS协议:网络世界的地址簿.md ├── 第19讲 HTTPDNS:网络世界的地址簿也会指错路.md └── 第20讲 CDN:你去小卖部取过快递么?.md ├── 第10讲 UDP协议:因性善而简单,难免碰到“城会玩.md ├── 第11讲 TCP协议(上):因性恶而复杂,先恶后善反轻松.md ├── 第12讲 TCP协议(下):西行必定多妖孽,恒心智慧消磨难.md ├── 第2讲 为什么要学习网络协议.md ├── 第3讲 ifconfig:最熟悉又陌生的命令行.md ├── 第4讲 DHCP与PXE,IP是怎么来的,又是怎么没的.md ├── 第5讲 从物理层到MAC层:如何在宿舍里自己组网玩联机游戏.md ├── 第6讲 交换机与VLAN.md ├── 第7讲 ICMP与ping_投石问路的侦察兵.md ├── 第8讲 世界这么大,我想出网关:欧洲十国游与玄奘西行.md └── 第9讲 路由协议:西出网关无故人,敢问路在何方.md /Android/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/.DS_Store -------------------------------------------------------------------------------- /Android/Android入门/10. Resources/Android xml 资源文件中 @、@android_type、@_、?、@+ 含义和区别.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://blog.csdn.net/mingli198611/article/details/7105850 2 | 3 | **Android  资源文件中 @、@android:type、@*、?、@+ 含义和区别** 4 | 5 | **一.@代表引用资源** 6 | 7 | **1\. 引用自定义资源。格式:@[package:]type/name** 8 | 9 | android:text="@string/hello" 10 | 11 | **2\. 引用系统资源。格式:@android:type/name** 12 | 13 |     android:textColor="@android:color/opaque_red" 14 | 15 |   注意:其实 **@android:type/name 是 @[package:]type/name 的一个子类** 16 | 17 | **二.@* 代表引用系统的非 public 资源。格式:@*android:type/name** 18 | 19 | 系统资源定义分 public 和非 public。public 的声明在: 20 | 21 |   \platforms\android-8\data\res\values\public.xml 22 | 23 |   **@*android:type/name:**可以调用系统定义的所有资源 24 | 25 | **  @android:type/name:**只能够调用 publi 属性的资源。 26 | 27 |   注意:没在 public.xml 中声明的资源是 google 不推荐使用的。 28 | 29 | **三.?代表引用主题属性** 30 | 31 |   另外一种资源值允许你引用当前主题中的属性的值。这个属性值只能在 style 资源和 XML 属性中使用;它允许你通过将它们改变为当前主题提供的标准变化来改变 UI 元素的外观,而不是提供具体的值。例如: 32 | 33 |   android:textColor="?android:textDisabledColor"  34 | 35 |    注意,这和资源引用非常类似,除了我们使用一个 "?" 前缀代替了 "@"。当你使用这个标记时,你就提供了属性资源的名称,它将会在主题中被查找,所以你不需要显示声明这个类型 (如果声明,其形式就是? android:attr/android:textDisabledColor)。除了使用这个资源的标识符来查询主题中的值代替原始的资源,其命名语法和 "@" 形式一致:?[namespace:]type/name,这里类型可选。 36 | 37 |  四**.@+ 代表在创建或引用资源 。格式:@+type/name** 38 | 39 |     含义:”+” 表示在 R.java 中名为 type 的内部类中添加一条记录。如 "@+id/button" 的含义是在 R.java 文件中的 id 这个静态内部类添加一条常量名为 button。该常量就是该资源的标识符。如果标示符(包括系统资源)已经存在则表示引用该标示符。最常用的就是在定义资源 ID 中,例如: 40 | 41 |  @+id / 资源 ID 名         新建一个资源 ID 42 | 43 |  @id / 资源 ID 名          应用现有已定义的资源 ID,包括系统 ID 44 | 45 |  @android:id / 资源 ID 名   引用系统 ID,其等效于 @id / 资源 ID 名 46 | 47 |  android:id="@+id/selectdlg" 48 | 49 |  android:id="@android:id/text1" 50 | 51 |  android:id="@id/button3" -------------------------------------------------------------------------------- /Android/Android入门/12. RxJava/RxJava原理.md: -------------------------------------------------------------------------------- 1 | 2 | https://juejin.im/post/5b1fbd796fb9a01e8c5fd847 -------------------------------------------------------------------------------- /Android/Android入门/12. RxJava/一句话总结RxJava.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | RxJava 其实就是提供一套异步编程的 API,这套 API 是基于观察者模式的,而且是链式调用的,所以使用 RxJava 编写的代码的逻辑会非常简洁。 而且还可以切换线程 -------------------------------------------------------------------------------- /Android/Android入门/15. Architecture components/引入Component.md: -------------------------------------------------------------------------------- 1 | 2 | ``` 3 | https://developer.android.google.cn/topic/libraries/architecture/adding-components.html 4 | 5 | def lifecycle_version = "2.0.0" 6 | 7 | // ViewModel and LiveData 8 | implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" 9 | ``` -------------------------------------------------------------------------------- /Android/Android入门/15. Architecture components/迁移到AndroidX.md: -------------------------------------------------------------------------------- 1 | 2 | 可以访问 https://developer.android.com/jetpack/androidx/migrate 3 | -------------------------------------------------------------------------------- /Android/Android入门/4. 动画和手势/动画知识脑图.mindmap: -------------------------------------------------------------------------------- 1 | {"nodes":[{"id":"root","topic":"动画","isroot":true,"expanded":true,"parentid":null,"style":{"left":"100px","top":"187px","display":"","visibility":"visible"},"customStyle":{},"expanderStyle":{},"view":{"width":"104px","height":"65px"},"images":[],"link":{}},{"id":"99d9c31d938f4a9f","topic":"属性动画","isroot":false,"expanded":true,"parentid":"root","style":{"left":"238px","top":"169px","display":"","visibility":"visible"},"customStyle":{"color":"black","fontSize":"16px","fontFamily":["Microsoft YaHei","STXihei"],"textDecoration":"","fontWeight":"normal","fontStyle":"normal"},"expanderStyle":{"display":"none","visibility":"hidden"},"view":{"width":"72px","height":"23px"},"images":[],"link":{}},{"id":"99d9c41c86563b80","topic":"View动画","isroot":false,"expanded":true,"parentid":"root","style":{"left":"238px","top":"227px","display":"","visibility":"visible"},"customStyle":{"color":"black","fontSize":"16px","fontFamily":["Microsoft YaHei","STXihei"],"textDecoration":"","fontWeight":"normal","fontStyle":"normal"},"expanderStyle":{"left":"315px","top":"233px","display":"","visibility":"visible"},"view":{"width":"77px","height":"23px"},"images":[],"link":{}},{"id":"99d9c6690a54af8c","topic":"补间动画","isroot":false,"expanded":true,"parentid":"99d9c41c86563b80","style":{"left":"362px","top":"208px","display":"","visibility":"visible"},"customStyle":{"color":"black","fontSize":"16px","fontFamily":["Microsoft YaHei","STXihei"],"textDecoration":"","fontWeight":"normal","fontStyle":"normal"},"expanderStyle":{"display":"none","visibility":"hidden"},"view":{"width":"72px","height":"23px"},"images":[],"link":{}},{"id":"99d9c7d98655dd0c","topic":"帧动画","isroot":false,"expanded":true,"parentid":"99d9c41c86563b80","style":{"left":"362px","top":"247px","display":"","visibility":"visible"},"customStyle":{"color":"black","fontSize":"16px","fontFamily":["Microsoft YaHei","STXihei"],"textDecoration":"","fontWeight":"normal","fontStyle":"normal"},"expanderStyle":{"display":"none","visibility":"hidden"},"view":{"width":"56px","height":"23px"},"images":[],"link":{}}],"remarks":{},"resourceList":"","zoom":1} -------------------------------------------------------------------------------- /Android/Android入门/6. 图片加载/Bitmap工具类.md: -------------------------------------------------------------------------------- 1 | 2 | 封装一些常用功能 3 | 4 | ```java 5 | class BitmapUtil { 6 | 7 | public static Bitmap getBitmapById(Context context, int resId) { 8 | if (context == null || resId <= 0) { 9 | return null; 10 | } 11 | BitmapFactory.Options options = new BitmapFactory.Options(); 12 | //搞成这个,变为2字节 比ARGB_8888节约一半的消耗 13 | options.inPreferredConfig = Bitmap.Config.RGB_565; 14 | options.inJustDecodeBounds = true; 15 | //我只是简单测量一下 解析bitmap只获取尺寸信息,不生成像素数据 16 | BitmapFactory.decodeResource(context.getResources(), resId, options); 17 | //现在可不是简单的测量了 18 | options.inJustDecodeBounds = false; 19 | //返回一个缩小的图像,以节约内存. 比如inSampleSize是4,那么宽高返回的是1/4,像素点是原来的1/16 必须是2的冥 20 | options.inSampleSize = BitmapUtil.computeSampleSize(options, 21 | PixelUtil.dp2px(context, 200), PixelUtil.dp2px(context, 150)); 22 | return BitmapFactory.decodeResource(context.getResources(), resId, options); 23 | } 24 | 25 | /** 26 | * @param options bitmap配置信息 27 | * @param desireWidth 目标宽度 28 | * @param desireHeight 目标高度 29 | * @return 合适的inSimpleSize 30 | */ 31 | public static int computeSampleSize(BitmapFactory.Options options, int desireWidth, int desireHeight) { 32 | if (options == null || desireWidth == 0 || desireHeight == 0) { 33 | return 1; 34 | } 35 | double radioW = options.outWidth * 1.0 / desireWidth; 36 | double radioH = options.outHeight * 1.0 / desireHeight; 37 | double minRadio = Math.min(radioW, radioH); 38 | double n = 1.0; 39 | //API中对于inSimpleSize的注释:最终的inSimpleSize应该为2的倍数,我们应该向上取与压缩比最接近的2的倍数。 40 | while (n <= minRadio) { 41 | n *= 2; 42 | } 43 | return (int) n; 44 | } 45 | } 46 | 47 | ``` -------------------------------------------------------------------------------- /Android/Android入门/6. 图片加载/tudo.md: -------------------------------------------------------------------------------- 1 | 2 | ① Android中Bitmap内存优化 - 简书 【推荐理由】深入浅出,告诉你一张图片到底占用多大内存 https://www.jianshu.com/p/3f6f6e4f1c88 3 | 4 | ② Android drawable微技巧,你所不知道的drawable的那些细节 - 郭霖的专栏 - ...【推荐理由】告诉你图片放在不同drawable目录下的差别,郭霖出品,这理由够充分吧 https://blog.csdn.net/guolin_blog/article/details/50727753 5 | 6 | ③ Android照片墙完整版,完美结合LruCache和DiskLruCache - 郭霖的专栏 - ... 【推荐理由】LruCache和DiskLruCache,图片的缓存策略,郭霖出品 https://blog.csdn.net/guolin_blog/article/details/34093441 7 | 8 | ④ Android DiskLruCache完全解析,硬盘缓存的最佳方案 - 郭霖的专栏 - CSDN博... 【推荐理由】DiskLruCache的原理,郭霖出品 https://blog.csdn.net/guolin_blog/article/details/28863651 -------------------------------------------------------------------------------- /Android/Android学习笔记/SVN 版本控制.md: -------------------------------------------------------------------------------- 1 | # 版本控制 2 | 3 | [TOC] 4 | 5 | # 1. 常见的版本控制软件 6 | 1. cvs 7 | 2. svn 8 | 3. ClearCase IBM的 9 | 4. vss 微软的 10 | 5. git 由很多台电脑组成了一个整体 11 | 12 | # 2. svn 单用户 管理代码 13 | 14 | 1. 让当前工作空间与svn服务器建立关联 15 | 16 | 17 | - 首先需要知道服务器仓库地址,然后到自己的工作空间,右键`SVN-Checkout`选项,输入仓库地址(里面的主机名称改为ip地址,PPP适配器), 18 | 点OK.输入用户名密码即可得到服务器上的代码,并且该工作空间文件夹会打上一个绿色的勾. 19 | 20 | 2. 如果发现当前工作空间有一个.svn目录就说明当前工作空间与仓库建立关联 21 | 3. 当前工作空间会有一个绿色的勾 22 | 23 | 24 | 4. 创建一个代码文件(eg:Test.java),右键点击add,则代码文件的图标会变成一个蓝色的`+` 25 | ,表示计划把文件加入到版本控制库中. 26 | 5. 把文件提交到版本库 27 | 28 | - 代码文件,右键`SVN-Commit`提交 29 | 30 | # 3. 版本库的备份与还原 31 | 默认仓库的位置在C盘的Repositories下(安装的时候让你选择的那个目录),可以拷贝一份拿来备份.上传到云盘等. 32 | 33 | # 4. SVN软件的基本使用 34 | 1. 查看提交日志 35 | 36 | * 代码文件右键`TortoiseSVN`->`show log`,即可查看该代码文件的所有提交过的记录,提交者,时间,注释等信息. 37 | * 点击下面的窗口,可以查看每一次提交的代码,点进去还可以查看这一次提交的代码和上一次有什么不同. 38 | 39 | 40 | 2. 清除账户信息 41 | 42 | * 如果之前提交代码的时候勾选了记住密码,则下一次不会要求再次输入用户名和密码.现在可以点击`TortoiseSVN`->`Settings`->`SavedData`进行`Clear`. 43 | 44 | 3. 安装了`VisualSVN Server`之后,开机不用打开这个软件,直接就可以提交代码,直接浏览器就可以访问`https://127.0.0.1/`.(前提是开启了VisualSVN Server服务) 45 | 46 | # 5. SVN多用户代码的控制 47 | 48 | - 多个用户创建不同的工作空间,在不同的地方. 49 | - 首先需要与仓库进行关联 50 | - 其次写完代码提交, 需要`SVN-Update`,这个表示更新仓库的代码到本地来. 51 | - 当遇到黄色三角形感叹号时,表示提交的代码有冲突.svn不知道用哪一份,此时点击右键,选择`TortoiseSVN`->`Edit conflicts`,会显示冲突的部分,此时编辑即可.上面2个窗口表示冲突的代码,下面是最终决定用哪个代码的窗口.如下所示: 52 | 53 | ![](http://p1.bqimg.com/567571/61dfb81c292d3743.png) 54 | 55 | 选中下面的窗口有问号的代码行,选择上面窗口中你觉得该用那行的代码,右键`use this text block`.这时那一行的代码就确定了. 56 | 57 | - SVN不是专门用来解决冲突的,有冲突的话,解决起来比较麻烦. 58 | - 提交代码之前要先更新一下,这样能避免冲突. 59 | - 在公司一般都是分模块了的,除了一些Utils是公共的. 60 | 61 | # 6. SVN常见图标 62 | 63 | - 绿色勾 代表和服务已经建立关联 或者 更新成功等 64 | - 蓝色? 代表服务器不知道有这个文件 65 | - 蓝色+ 代表计划加入到版本库中 66 | - 黄色! 代表遇到了冲突 67 | - 红色! 代表修改了这个文件,需要提交到版本控制库中 68 | - 灰色勾 代表文件只读 69 | - 锁在开发中慎用 70 | 71 | # 7. SVN原则 72 | 73 | - **先更新再提交** 74 | - 多提交,经常提交,经常提交!!! 每次提交的间隔短一些,加了一个小功能或者UI就提交一次. 75 | - 不要提交不能通过编译的代码 Android只要是有一个编译时错误,就不能右键部署. 76 | - 每次提交必须书写明晰的标注 77 | - 提交时注意不要提交本地自动生成的文件 Android比如`bin`和`gen`目录 78 | 79 | * 选中`bin`和`gen`目录,右键`TortoiseSVN`->`Unversion and add to ignore list`->`delete and ignore 2 items by name` 80 | 81 | - 不要提交自己不明白的代码 82 | - **慎用锁定功能** 83 | 84 | # 8. 使用SVN管理Android项目 85 | 86 | >使用ignore忽略不想提交的目录 87 | 88 | 1. 使用客户端软件 89 | 2. 使用eclipse插件 90 | 91 | # 9. svn的标准目录结构 92 | 93 | 1. trunk 标准目录结构 94 | 2. branches 分支 一般用来修复bug 95 | 3. tags 里程碑 比如发布了一个稳定的版本 -------------------------------------------------------------------------------- /Android/Android学习笔记/公司的一些习惯.md: -------------------------------------------------------------------------------- 1 | #公司的一些习惯 2 | 3 | [TOC] 4 | 5 | # 1.命名 6 | 7 | 1. 开始界面一般都叫`splash`(`activity_splash`) 8 | 2. 服务 `XxService` 9 | 3. 活动 `XxActivity` `activity_main` 10 | 4. 内容提供者 `XxProvider` 11 | 5. 广播接收器 `XxReceiver` 12 | 6. 碎片 `fragment_xx` 13 | 7. 类的属性 `mHandler` 一般是m开头,然后接单词的首字母大写 14 | 8. ListView或RecyclerView子项 item_msg_layout 15 | 16 | # 2.常见包名 17 | 18 | 1. `bean` `model` 一个模型 19 | 2. `util` 工具类 20 | 3. `adapter` 适配器的包 21 | 4. `dao` `db` 操作数据库的包 帮助类和增删改查的类 22 | 5. `view` `ui.widget` 自定义的控件 23 | 6. `net` 网络 24 | 7. `activities` 页面用到的Activity类 (activities层级名用户界面层) 25 | 8. `base` 基础共享的类,如多个Activity共享的 26 | BaseActivity或整个应用共享的MyApplication类 27 | 9. `service` Service服务 28 | 10. `broadcast` BroadcastReceiver广播 29 | 30 | # 3.SharedPreferences 31 | 32 | > 一般都封装了一个工具类(eg:SharedUtils) 33 | 34 | # 4.给你个项目一般先从清单文件开始看(AndroidManifest.xml),然后看Intent-Filter MAIN 35 | 36 | # 5. Log的使用 37 | 38 | - 一般tag都是当前类所对应的名称 39 | - Log一般会封装到LogUtil中,方便在发布的时候关闭log. 40 | 41 | # 6. `Toast`的使用 42 | 43 | > 可以将`Toast`的使用封装到`ToastUtil`类里面的`show()`方法里面 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/AIDL简单使用.md: -------------------------------------------------------------------------------- 1 | # AIDL简单使用 2 | 3 | ## 1. 在Android Studio下的简单配置 4 | 5 | 1. 需要在src/main下新建一个aidl文件夹 6 | 2. 然后把aidl文件放在这下面即可(如果有包名,则还需要在里面新建package). 7 | 8 | ## 2. AIDL用来做什么 9 | 10 | AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写,对于小白来说,AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互。 11 | 12 | ## 3. 最后 13 | 14 | 为什么APP间的进程交互这么麻烦,是因为它们属于不同的进程,之间的交互涉及到进程间的通讯。 15 | 而AIDL只是Android中众多进程间通讯方式中的一种方式 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Activity向Fragment传值 大坑.md: -------------------------------------------------------------------------------- 1 | 今天在看别人的代码时,发现Activity向Fragment中传值时是用的set()方法....我以为是对的,后来踩了各种坑,,,, 2 | 3 | 正确做法:Activity向Fragment中传值应该用setArguments() 不然会发生各种各样奇形怪状的问题........... -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Activity生命周期.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![](https://developer.android.com/images/activity_lifecycle.png) 4 | 5 | - onCreate() 6 | - onRestart() 7 | - onStart() 8 | - onResume() 9 | - onPause() 10 | - onStop() 11 | - onDestroy() -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Android DecorView浅析.md: -------------------------------------------------------------------------------- 1 | # Android DecorView浅析 2 | 3 | > 原作:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0322/1054.html 4 | 5 | 一、DecorView为整个Window界面的最顶层View。 6 | 7 | 二、DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。 8 | 9 | 三、LinearLayout里有两个FrameLayout子元素。 10 | 11 | (20)为标题栏显示界面。只有一个TextView显示应用的名称。也可以自定义标题栏,载入后的自定义标题栏View将加入FrameLayout中。 12 | 13 | (21)为内容栏显示界面。就是setContentView()方法载入的布局界面,加入其中。 14 | 15 | 设置自定义的TItleBar 16 | 17 | requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); 18 | setContentView(R.layout.custom_title); 19 | getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_1); 20 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Android View的点击事件无效.md: -------------------------------------------------------------------------------- 1 | # Android View的点击事件无效 解决办法 2 | 3 | > 背景:有时候一个控件,即设置了点击事件监听器setOnClickListener(this);,又设置了setOnTouchListener(this); 这个时候点击事件就会无效. 4 | 5 | 解决方案:当即需要监听点击事件 又需要监听触摸事件 onTouch()必须返回false,否则点击事件无效 6 | 7 | public boolean onTouch(View v, MotionEvent event) { 8 | switch (event.getAction()) { 9 | case MotionEvent.ACTION_DOWN: //按下 10 | break; 11 | case MotionEvent.ACTION_MOVE: //移动 12 | break; 13 | case MotionEvent.ACTION_UP: //抬起 14 | break; 15 | default: 16 | break; 17 | } 18 | 19 | //当即需要监听点击事件 又需要监听触摸事件 这里必须返回false,否则点击事件无效 20 | return false; 21 | } 22 | 23 | public void onClick(View v) { 24 | switch (v.getId()) { 25 | case R.id.iv_drag: //处理iv_drag的点击事件 26 | ToastUtil.show("你点我了"); 27 | break; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Android 多击事件.md: -------------------------------------------------------------------------------- 1 | # Android 多击事件 2 | 3 | > 需求:有时候需要做控件的多击事件 4 | 5 | > 分析:声明一个数组,每点击一次,就将数据放到最后一位上.每一次都将从第二位开始数据往前挪一位 这样最后判断之间的差值(第1下和第5下是否间隔小于500毫秒),差值小于500,就做点事情. 6 | 7 | # 一.直接上代码 8 | 9 | public class MainActivity extends Activity implements OnClickListener { 10 | 11 | private ImageView iv_girl; 12 | private long mHits[] = new long[5]; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | 19 | iv_girl = (ImageView) findViewById(R.id.iv_girl); 20 | iv_girl.setOnClickListener(this); 21 | 22 | } 23 | 24 | @Override 25 | public void onClick(View v) { 26 | 27 | System.arraycopy(mHits, 1, mHits, 0, mHits.length-1); 28 | mHits[mHits.length-1] = SystemClock.uptimeMillis(); 29 | if(mHits[mHits.length-1]-mHits[0]<500){ 30 | Toast.makeText(this, "果然是真男人!!!!!!\n送你一张美图", Toast.LENGTH_SHORT).show(); 31 | } 32 | } 33 | 34 | } 35 | 36 | 37 | 如图: 38 | ![](http://olg7c0d2n.bkt.clouddn.com/17-5-3/22588509-file_1493779116748_153bc.png) 39 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Android 未root查看ANR异常.md: -------------------------------------------------------------------------------- 1 | 2 | > 有时候APP不抛出错误,但是会抛出ANR。 3 | 4 | 一般我们的APP出现ANR后会将ANR信息保存到`/data/anr/traces.txt`里面。 5 | 6 | 在系统里面配置环境变量:adb,然后打开命令行,输入 7 | 8 | ``` 9 | 方式1: 10 | cd data/ 进入data目录 11 | cd anr/ 进入anr目录 12 | ls 可以看到之前产生的traces.txt文件 13 | cat traces.txt 查看文件内容,当然也可以push到电脑上慢慢看 14 | 15 | 16 | 方式2: 17 | adb pull /data/anr . 直接将anr下面的全部文件push到电脑上,如果是windows的话在C:\Users\用户名\anr下面 18 | ``` -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Android平台架构.md: -------------------------------------------------------------------------------- 1 | # Android平台架构 2 | 3 | > Android 是一种基于 Linux 的开放源代码软件栈,为广泛的设备和机型而创建。下图所示为 Android 平台的主要组件。 4 | 5 | ![](https://developer.android.com/guide/platform/images/android-stack_2x.png) 6 | 7 | ## Linux 内核 8 | 9 | Android 平台的基础是 Linux 内核。例如,Android Runtime (ART) 依靠 Linux 内核来执行底层功能,例如线程和低层内存管理。 10 | 11 | 使用 Linux 内核可让 Android 利用主要安全功能,并且允许设备制造商为著名的内核开发硬件驱动程序。 12 | 13 | ## 硬件抽象层 (HAL) 14 | 15 | 硬件抽象层 (HAL) 提供标准界面,向更高级别的 Java API 框架显示设备硬件功能。HAL 包含多个库模块,其中每个模块都为特定类型的硬件组件实现一个界面,例如相机或蓝牙模块。当框架 API 要求访问设备硬件时,Android 系统将为该硬件组件加载库模块。 16 | 17 | ## Android Runtime 18 | 19 | 对于运行 Android 5.0(API 级别 21)或更高版本的设备,每个应用都在其自己的进程中运行,并且有其自己的 Android Runtime (ART) 实例。ART 编写为通过执行 DEX 文件在低内存设备上运行多个虚拟机,DEX 文件是一种专为 Android 设计的字节码格式,经过优化,使用的内存很少。编译工具链(例如 Jack)将 Java 源代码编译为 DEX 字节码,使其可在 Android 平台上运行。 20 | 21 | ART 的部分主要功能包括: 22 | 23 | 预先 (AOT) 和即时 (JIT) 编译 24 | 优化的垃圾回收 (GC) 25 | 更好的调试支持,包括专用采样分析器、详细的诊断异常和崩溃报告,并且能够设置监视点以监控特定字段 26 | 在 Android 版本 5.0(API 级别 21)之前,Dalvik 是 Android Runtime。如果您的应用在 ART 上运行效果很好,那么它应该也可在 Dalvik 上运行,但反过来不一定。 27 | 28 | Android 还包含一套核心运行时库,可提供 Java API 框架使用的 Java 编程语言大部分功能,包括一些 Java 8 语言功能。 29 | 30 | ## 原生 C/C++ 库 31 | 32 | 许多核心 Android 系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的原生库。Android 平台提供 Java 框架 API 以向应用显示其中部分原生库的功能。例如,您可以通过 Android 框架的 Java OpenGL API 访问 OpenGL ES,以支持在应用中绘制和操作 2D 和 3D 图形。 33 | 34 | 如果开发的是需要 C 或 C++ 代码的应用,可以使用 Android NDK 直接从原生代码访问某些原生平台库。 35 | 36 | ## Java API 框架 37 | 38 | 您可通过以 Java 语言编写的 API 使用 Android OS 的整个功能集。这些 API 形成创建 Android 应用所需的构建块,它们可简化核心模块化系统组件和服务的重复使用,包括以下组件和服务: 39 | 40 | 丰富、可扩展的视图系统,可用以构建应用的 UI,包括列表、网格、文本框、按钮甚至可嵌入的网络浏览器 41 | 资源管理器,用于访问非代码资源,例如本地化的字符串、图形和布局文件 42 | 通知管理器,可让所有应用在状态栏中显示自定义提醒 43 | Activity 管理器,用于管理应用的生命周期,提供常见的导航返回栈 44 | 内容提供程序,可让应用访问其他应用(例如“联系人”应用)中的数据或者共享其自己的数据 45 | 开发者可以完全访问 Android 系统应用使用的框架 API。 46 | 47 | ## 系统应用 48 | 49 | Android 随附一套用于电子邮件、短信、日历、互联网浏览和联系人等的核心应用。平台随附的应用与用户可以选择安装的应用一样,没有特殊状态。因此第三方应用可成为用户的默认网络浏览器、短信 Messenger 甚至默认键盘(有一些例外,例如系统的“设置”应用)。 50 | 51 | 系统应用可用作用户的应用,以及提供开发者可从其自己的应用访问的主要功能。例如,如果您的应用要发短信,您无需自己构建该功能,可以改为调用已安装的短信应用向您指定的接收者发送消息。 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Android平台架构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android学习笔记/杂乱的知识点/Android平台架构.png -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Android系统自带的常用数据库.md: -------------------------------------------------------------------------------- 1 | # Android系统自带的常用的数据库 2 | 3 | ## 1. 联系人数据 4 | 5 | data/data/com.android.providers.contacts/databases/contacts2.db 6 | 7 | 1.当需要读取通话记录的时候,需要用到系统的数据库,现在需要去查看源码Android清单文件(路径:`android-7.0.0_r1\packages\providers\ContactsProvider\AndroidManifest`)中,看到 8 | 9 | 15 | 16 | 17 | 2.可以看到,里面的android:authorities="call_log",所以访问数据库中calls表的Uri地址: `content://call_log/calls`. 18 | 19 | - 中间的那个call_log是根据源码中的android:authorities="call_log"来的 20 | - 最后那个calls是表名,需要去源码 21 | `android-7.0.0_r1\packages\providers\ContactsProvider\src\com\android\providers\contacts\CallLogProvider.java中`查看 22 | 23 | static { 24 | sURIMatcher.addURI(CallLog.AUTHORITY, "calls", CALLS); 25 | ... 26 | } 27 | 3.从上面的源码中可以看到,写url的时候只需要在authorities后面加上calls即可访问通话记录这张表.访问其他的数据库也是同样的道理. 28 | 29 | ## 2.短信数据 30 | 31 | data/data/com.android.providers.telephony/databases/mmssms.db/sms 32 | 33 | 获取其相应的四个字段(address 电话号码 date 时间 type:接收,发送 body:短信内容) 34 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Bundle.md: -------------------------------------------------------------------------------- 1 | # Bundle 2 | 3 | # 1. 使用Bundle传递对象 4 | 5 | 1.让对象实现Serializable 6 | 2.数据封装 7 | 8 | Bundle bundle = new Bundle(); 9 | TabData tabData = new TabData(); 10 | //将对象封装到Bundle对象中 11 | bundle.putSerializable(CONTENT_DATA_KEY,tabData); 12 | 13 | 3.取出数据 14 | 15 | Bundle bundle = getArguments(); 16 | if (bundle != null) { 17 | // 从bundle数据包中取出数据 18 | TabData tabData = (TabData) bundle.getSerializable(CONTENT_DATA_KEY); 19 | } 20 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/CheckBox代码去掉小方框.md: -------------------------------------------------------------------------------- 1 | CheckBox checkBox = new CheckBox(context); 2 | checkBox.setButtonDrawable(new ColorDrawable(Color.TRANSPARENT));// 通过透明度的方式. -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/DialogFragment全屏.md: -------------------------------------------------------------------------------- 1 | 2 | ## 方式1: 3 | 4 | ```kotlin 5 | class HomeFullInviteDialog : DialogFragment() { 6 | 7 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 8 | return inflater.inflate(R.layout.dialog_home_full_invite, container, false) 9 | } 10 | 11 | override fun onActivityCreated(savedInstanceState: Bundle?) { 12 | val window = dialog.window 13 | window?.requestFeature(Window.FEATURE_NO_TITLE) 14 | super.onActivityCreated(savedInstanceState) 15 | window?.setBackgroundDrawable(ColorDrawable(0x00000000)) 16 | window?.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT) 17 | } 18 | 19 | } 20 | ``` 21 | 22 | ## 方式2: 23 | 第一步在style中定义全屏Dialog样式 24 | ``` 25 | 30 | ``` 31 | 第二步:设置样式,以DialogFragment为例,只需要在onCreate中setStyle(STYLE_NORMAL, R.style.Dialog_FullScreen)即可。(推荐使用DialogFragment,它复用了Fragment的声明周期,被杀死后,可以恢复重建) 32 | ``` 33 | public class FragmentFullScreen extends DialogFragment { 34 | 35 | @Override 36 | public void onCreate(@Nullable Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setStyle(STYLE_NORMAL, R.style.Dialog_FullScreen); 39 | } 40 | } 41 | ``` 42 | 如果是在Dialog中,设置如下代码即可。 43 | ``` 44 | public class FullScreenDialog extends Dialog { 45 | public FullScreenDialog(Context context) { 46 | super(context); 47 | getWindow().requestFeature(Window.FEATURE_NO_TITLE); 48 | } 49 | } 50 | ``` -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/DialogFragment遇到的坑.md: -------------------------------------------------------------------------------- 1 | # DialogFragment 2 | 3 | > 平时使用对话框时,如果需要输入值,或者是其他什么很多的操作,官方建议操作DialogFragment. 4 | 5 | 平时在使用时,其实是好好的,今天我突发奇想,快速得点击按钮让DialogFragment快速的显示隐藏,于是,,,,程序就崩溃了....no zuo no die,,哈哈,崩溃这么大的bug,必须修复. 6 | 7 | 报错信息如下: 8 | 9 | ```java 10 | java.lang.IllegalStateException: Fragment already added: FilterDialogFragment{2ba55429 #1 } 11 | at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1892) 12 | at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:760) 13 | at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2590) 14 | at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2377) 15 | at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2332) 16 | at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2239) 17 | at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:700) 18 | at android.os.Handler.handleCallback(Handler.java:739) 19 | at android.os.Handler.dispatchMessage(Handler.java:95) 20 | at android.os.Looper.loop(Looper.java:135) 21 | at android.app.ActivityThread.main(ActivityThread.java:5418) 22 | at java.lang.reflect.Method.invoke(Native Method) 23 | at java.lang.reflect.Method.invoke(Method.java:372) 24 | at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1037) 25 | at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832) 26 | ``` 27 | 28 | 可以看到是重复添加了,解决办法:判断是否已经添加了DialogFragment. 29 | ```java 30 | if (mFilterDialogFragment == null) { 31 | mFilterDialogFragment = FilterDialogFragment.newInstance(mHKeywordsRes); 32 | } else if(!mFilterDialogFragment.isAdded()){ 33 | mFilterDialogFragment.show(getSupportFragmentManager(), ""); 34 | } 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Handler 总结.md: -------------------------------------------------------------------------------- 1 | # Handler 总结 2 | 3 | ## Handler 4 | 5 | - 发送消息,它能把消息发送给Looper管理的MessageQueue。 6 | 7 | - 处理消息,并负责处理Looper分给它的消息。 8 | 9 | - Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。  10 | 11 | - Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。   12 | 13 | ## Looper 14 | 15 | - 每个线程只有一个Looper,它负责管理对应的MessageQueue,会不断地从MessageQueue取出消息,并将消息分给对应的Hanlder处理。   16 | 17 | - 主线程中,系统已经初始化了一个Looper对象,因此可以直接创建Handler即可,就可以通过Handler来发送消息、处理消息。 程序自己启动的子线程,程序必须自己创建一个Looper对象,并启动它,调用Looper.prepare()方法。 18 | 19 | - prapare()方法:保证每个线程最多只有一个Looper对象。   20 | 21 | - looper()方法:启动Looper,使用一个死循环不断取出MessageQueue中的消息,并将取出的消息分给对应的Handler进行处理。   22 | 23 | ## MessageQueue 24 | 25 | - 由Looper负责管理,它采用先进先出的方式来管理Message。  26 | 27 | ## Message 28 | 29 | - Handler接收和处理的消息对象。 30 | 31 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Kotlin配合Gson进行json数据解析.md: -------------------------------------------------------------------------------- 1 | # Kotlin配合Gson进行json数据解析 2 | 3 | > 昨天写的小demo里使用到了这个 4 | 5 | # 1,首先引入第3方库 6 | 7 | implementation 'com.squareup.okhttp3:okhttp:3.8.1' 8 | implementation 'io.reactivex.rxjava2:rxjava:2.1.2' 9 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' 10 | implementation 'com.google.code.gson:gson:2.8.1' 11 | 12 | # 2,正式开始解析 13 | 14 | ``` java 15 | 16 | //使用Gson解析json数据 17 | val gson = Gson() 18 | //NewsResponse::class.java 表示Java的class 19 | //这里的NewsResponse是model对象(数据模型) 20 | val newsResponse = gson.fromJson(response, NewsResponse::class.java) 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/MVP初识.md: -------------------------------------------------------------------------------- 1 | # MVP基本认识 2 | 3 | # data 4 | 5 | > 一般用于请求数据,或者处理数据 6 | 7 | 比如ApplicationFormRepository中有个getApplicationForm()接口方法; 8 | 9 | 那么在ApplicationFormRepositoryImpl需要实现该方法,并去请求网络,获取model数据. 10 | 11 | 12 | # model 13 | 14 | > 就是模型类,比如请求参数模型类,获取服务器返回的数据的模型类都行 15 | 16 | # presenter 17 | 18 | > 控制data和view,用data的示例去请求数据,用view进行显示 19 | 20 | 在这里面,有data的实现类的实例.和view的实体类 21 | 22 | ChooseApplyContract(presenter的接口)->ChooseApplyPresenter(presenter实现) 23 | 24 | ChooseApplyContract写一些接口方法 25 | 26 | 并在ChooseApplyContract中定义一个IView接口, 27 | 28 | interface IView extends BaseView { 29 | /** 30 | * 查询申请单结果回调 31 | * @param responseVo 32 | */ 33 | void renderChooseAppForm(List responseVo); 34 | } 35 | 36 | 这里将BaseView提取出来,BaseView也是一个接口,它是任何MVP的view的父接口, 37 | 它里面包含2个公用的接口,用来显示错误信息的. 38 | 39 | public interface BaseView { 40 | 41 | void showErrorMsg(String msg); 42 | 43 | void showErrorView(String msg); 44 | } 45 | 46 | # view 47 | 48 | > 这里的view一般就是Activity或者Fragment等等.里面有一个presenter实例,然后通过presenter去请求数据获取其他操作. 49 | 50 | 在view对象里面是只负责做界面的显示的,比如 51 | 52 | - showErrorView(); 53 | 54 | - showLoading(); 55 | 56 | - showBookList(); 57 | 58 | view是需要实现presenter里面的IView接口的,方便通过presenter去调用. -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Notification通知.md: -------------------------------------------------------------------------------- 1 | 2 | ## 自定义通知 3 | 4 | ```kotlin 5 | val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 6 | 7 | val intent = Intent(this,MainActivity::class.java) 8 | val pendingIntent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT) 9 | val remoteViews = RemoteViews(packageName,R.layout.layout_notification) 10 | remoteViews.setTextViewText(R.id.mTextTv,"xfhy") 11 | remoteViews.setImageViewResource(R.id.mRmIv,R.drawable.ic_android) 12 | 13 | //可以设置某个控件的点击事件 14 | // remoteViews.setOnClickPendingIntent(R.id.mOpenDemoTv,pendingIntent) 15 | 16 | val notification = NotificationCompat.Builder(this) 17 | .setSmallIcon(R.drawable.ic_android) 18 | .setPriority(NotificationManager.IMPORTANCE_HIGH) 19 | .setAutoCancel(true) 20 | .setContent(remoteViews) 21 | .setContentIntent(pendingIntent) 22 | .build() 23 | manager.notify(2, notification) 24 | ``` -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/RxJava2操作符.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android学习笔记/杂乱的知识点/RxJava2操作符.png -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/Viewpager中的Fragment的生命周期.md: -------------------------------------------------------------------------------- 1 | # ViewPager中的Fragment生命周期 2 | 3 | ## 今天踩了个巨坑.... 4 | 5 | 当我在使用ViewPager+fragment时,我在一个ViewPager中放置了4个fragment,这时fragment的生命周期是很无语的.... 6 | 7 | 比如我从第一个fragment切换到第二个fragment(就是ViewPager滑动了一下),然后第一个fragment的生命周期居然不回调onPause(),也不回调onStop(); 8 | 9 | 这是我最后才发现的一个坑,最开始我一直以为是我代码的问题.... 10 | 11 | 放在这里,引以为戒,希望以后不要再碰这个坑.... 12 | 13 | ## 离开fragment需要做一下操作 14 | 15 | 当我需要离开第一个fragment时,我需要停止轮播图的切换,这时,我需要判断当前这个fragment是否对用户可见. 16 | 显然这时不能用onPause()去实现. 17 | 18 | ## 解决方案 19 | 20 | - 方案1:设置Viewpager的缓存机制,不缓存除当前页以外的页面数据,所见即所得,离开即销毁; 21 | 此方案对需求改动较大,且较影响用户体验; 22 | 23 | - 方案2:重载Fragment.onHiddenChanged(boolean hidden)方法,其参数hidden代表当前fragment显隐状态改变时,是否为隐藏状态,可通过check此参数作处理; 24 | 此方案局限在于本方法的系统调用时间发生在显隐状态改变时,但第一次显示时此方法并不调用; 25 | 26 | - 方案3:重载Fragment.setUserVisibleHint(boolean isVisibleToUser)方法,其参数isVisibleToUser顾名思义最接近我们的需求,代表页面是否“真正”对使用者显示; 27 | 此方案局限在于此方法的第一次系统调用甚至早于Fragment的onCreate方法,故其第一次调用时isVisibleToUser值总为false,影响我们对生命周期顺序的判定; 28 | ```java 29 | Fragment1 - isVisibleToUser - false (多余) 30 | Fragment1 - isVisibleToUser - true 31 | Fragment1 - isVisibleToUser - false 32 | Fragment2 - isVisibleToUser - false (多余) 33 | Fragment2 - isVisibleToUser - true 34 | Fragment2 - isVisibleToUser - false 35 | ``` 36 | 37 | ## 实际采用的解决方案 38 | 39 | 根据对产品需求的理解和用户体验的统一,选择在方案3基础上加以改进; 40 | setUserVisibleHint()方法本身很接近我们的需求,它的局限点我采取了一个侵入式的解决方式: 41 | ```java 42 | protected boolean isCreated = false; 43 | 44 | @Override 45 | public void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | 48 | // ... 49 | isCreated = true; 50 | } 51 | 52 | /** 53 | * 此方法目前仅适用于标示ViewPager中的Fragment是否真实可见 54 | * For 友盟统计的页面线性不交叉统计需求 55 | */ 56 | @Override 57 | public void setUserVisibleHint(boolean isVisibleToUser) { 58 | super.setUserVisibleHint(isVisibleToUser); 59 | 60 | if (!isCreated) { 61 | return; 62 | } 63 | 64 | if (isVisibleToUser) { 65 | umengPageStart(); 66 | }else { 67 | umengPageEnd(); 68 | } 69 | 70 | } 71 | ``` 72 | 对onCreate方法结束的一个标记即可解决问题; 73 | 切记:此标记的改变请勿放在Fragment的onActivtyCreate方法中,此方法调用滞后于setUserVisibleHint的判断 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/fragment生命周期.md: -------------------------------------------------------------------------------- 1 | # fragment生命周期 2 | 3 | ![](https://developer.android.com/images/fragment_lifecycle.png) 4 | 5 | - onAttach() 6 | - onCreate(Bundle) 7 | - onCreateView() 8 | - onActivityCreated(Bundle) 9 | - onStart() 10 | - onResume() 11 | - onPause() 12 | - onStop() 13 | - onDestroyView() 14 | - onDestroy() 15 | - onDetach() -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/xutils3基本使用.md: -------------------------------------------------------------------------------- 1 | # xutils3基本使用 2 | 3 | ## 1.引入依赖 4 | 5 | `使用compile 'org.xutils:xutils:3.4.0',这个版本要旧一点,但是比3.5.0更加兼容更多的机型` 6 | 7 | ## 2.使用xUtils3加载图片 8 | 9 | //简单加载,用户体验不好 10 | //x.image().bind(mImage,image_url); 11 | 12 | //建造者模式 设置ImageOptions 13 | ImageOptions.Builder builder = new ImageOptions.Builder(); 14 | //设置加载中的图片 15 | builder.setLoadingDrawableId(R.drawable.loading); 16 | //设置加载失败显示的图片 17 | builder.setFailureDrawableId(R.drawable.error); 18 | //设置为渐变进入 19 | builder.setFadeIn(true); 20 | //裁剪图片为圆形 21 | builder.setCircular(true); 22 | ImageOptions build = builder.build(); 23 | 24 | //加载图片 25 | x.image().bind(mImage,image_url,build); 26 | 27 | 上面的加载图片默认有缓存..下一次即使没网络依然可以加载成功 28 | 29 | ## 3.xutils3用get方式请求网络数据 30 | 31 | //构建请求参数信息 32 | RequestParams requestParams = new RequestParams(json_url); 33 | //发送请求,在回调中处理结果 34 | x.http().get(requestParams, new Callback.CommonCallback() { 35 | @Override 36 | public void onSuccess(String result) { 37 | Log.d(TAG, "onSuccess: result--" + result); 38 | 39 | //将json数据转换成java bean 40 | Gson gson = new Gson(); 41 | MovieListBean movieListBean = gson.fromJson(result, MovieListBean.class); 42 | Log.d(TAG, "onSuccess: "+movieListBean.toString()); 43 | } 44 | 45 | @Override 46 | public void onError(Throwable ex, boolean isOnCallback) { 47 | Log.d(TAG, "onError: " + ex.getMessage() + ex.getCause() + ex 48 | .getStackTrace() + ex.getLocalizedMessage()); 49 | } 50 | 51 | @Override 52 | public void onCancelled(CancelledException cex) { 53 | Log.d(TAG, "onCancelled: "); 54 | } 55 | 56 | @Override 57 | public void onFinished() { 58 | Log.d(TAG, "onFinished: "); 59 | } 60 | }); 61 | 62 | 63 | **上面的onSuccess()是在主线程中的..** -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/使用GSON解析json数据.md: -------------------------------------------------------------------------------- 1 | # 使用GSON解析json数据 2 | 3 | - 将json数据转换成java bean 4 | 5 | Gson gson = new Gson(); 6 | MovieListBean movieListBean = gson.fromJson(result, MovieListBean.class); 7 | 8 | # 1.常见错误 9 | 10 | **使用GSON一直报错** 11 | 12 | **com.google.gson.JsonSyntaxException: Java.lang.IllegalStateException: closed** 13 | 14 | 15 | 解决:OkHttp请求,response.body().string()只能调用一次 16 | 17 | # 2.序列化时排除字段的几种方式 18 | 19 | - 排除transient字段 给字段加上transient修饰符就可以了 20 | - 使用@Expose注解 21 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/使用Kotlin配合RxJava网络请求.md: -------------------------------------------------------------------------------- 1 | # 使用 Kotlin 配合 RxJava 进行网络请求 2 | 3 | ## 1.首先需要配置Kotlin在项目中 4 | 5 | - Android Studio 3.0是自带的,可以在创建项目的时候勾选include kotlin support 6 | - Android Studio 2.0+是需要自己配置的,首先需要安装Kotlin插件,然后在下图这里配置一下,Configure Kotlin in Project 7 | 8 | ![](http://olg7c0d2n.bkt.clouddn.com/17-8-4/72052612.jpg) 9 | 10 | 如果在配置了Kotlin,然后gradle 构建时下载慢,可以看看这里 [解决Android Studio配置完Kotlin下载慢的问题](http://blog.csdn.net/xfhy_/article/details/76628292) 11 | 12 | ## 2.引入第3方库 13 | 14 | > 我这里使用的是 OkHttp3,RxJava2,RxAndroid 15 | 16 | 引入如下(在我使用时,这是最新的版本): 17 | 18 | - implementation 'com.squareup.okhttp3:okhttp:3.8.1' 19 | - implementation 'io.reactivex.rxjava2:rxjava:2.1.2' 20 | - implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' 21 | - implementation 'com.google.code.gson:gson:2.8.1' 22 | - implementation 'com.github.bumptech.glide:glide:4.0.0' 23 | 24 | ## 3.正式开始写代码 25 | 26 | 在MainActivity中写入如下代码 27 | 28 | //使用RxJava处理 29 | Observable.create(ObservableOnSubscribe { 30 | e -> 31 | 32 | //使用okhttp3访问网络 33 | val builder = Request.Builder() 34 | val request = builder.url(NEWS_URL).get().build() 35 | val response = client.newCall(request).execute() 36 | val responseBody = response.body() 37 | val result = responseBody?.string() 38 | //这里的.string()只能用一次 如果下面那一句不注释的话就会报错 39 | //val result2 = responseBody?.string() 40 | 41 | Log.e(TAG, result) 42 | 43 | //这里其实形参是String类型,然而实参是String?类型,如果直接传result会报错,在后面加!!即可解决 44 | //发射(这里是被观察者,被观察者发射事件) 45 | e.onNext(result!!) 46 | 47 | //上面那句代码可以这样写 48 | //e.onNext(result as String) 49 | }).subscribeOn(Schedulers.io()) //io线程 被观察者 50 | .observeOn(AndroidSchedulers.mainThread()) //主线程 观察者 51 | .subscribe({ 52 | 53 | //这里接收刚刚被观察者发射的事件 54 | //这个response就是io线程发射过来的result 55 | response -> 56 | Log.e(TAG, response) 57 | }) 58 | 59 | ## 简简单单的总结 60 | 61 | 看似代码极少的demo,可是我却遇到了很多的挫折,,搞了好久好久才写好,主要是遇到错误的话,这种东西网上不好找解决方案.... 62 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/全屏.md: -------------------------------------------------------------------------------- 1 | # 全屏 2 | 3 | ## 1. 方式1:改values/style.xml 4 | 5 | 6 | 15 | 16 | ## 2. 方式2:在代码中写 17 | 18 | /*set it to be no title*/ 19 | requestWindowFeature(Window.FEATURE_NO_TITLE); 20 | 21 | /*set it to be full screen*/ 22 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 23 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 24 | 25 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/切换全屏,取消全屏.md: -------------------------------------------------------------------------------- 1 | # 切换全屏,取消全屏 2 | 3 | /** 4 | * 切换全屏,取消全屏 5 | * 6 | * @param isChecked 7 | */ 8 | private void switchFullScreen(boolean isChecked) { 9 | if (isChecked) { 10 | //切换到全屏模式 11 | //添加一个全屏的标记 12 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 13 | //请求横屏 14 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 15 | 16 | //设置视频播放控件的布局的高度是match_parent 17 | FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mVideoRootView.getLayoutParams(); 18 | //将默认的高度缓存下来 19 | mVideoHeight = layoutParams.height; 20 | layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; 21 | mVideoRootView.setLayoutParams(layoutParams); 22 | } else { 23 | //切换到默认模式 24 | //清除全屏标记 25 | getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 26 | //请求纵屏 27 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 28 | 29 | //设置视频播放控件的布局的高度是200 30 | FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mVideoRootView.getLayoutParams(); 31 | layoutParams.height = mVideoHeight; //这里的单位是px 32 | mVideoRootView.setLayoutParams(layoutParams); 33 | } 34 | } 35 | 36 | **横竖屏切换时的生命周期总结:** 37 | 38 | 1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次 39 | 40 | 2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次 41 | 42 | 3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/加密.md: -------------------------------------------------------------------------------- 1 | # 加密 2 | 3 | # 1.MD5加密 4 | 5 | > 为了安全保存密码, 可以md5算法, md5是一种不可逆的加密算法 6 | 7 | public static void main(String[] args) { 8 | try { 9 | String password = "123456"; 10 | MessageDigest digest = MessageDigest.getInstance("MD5"); 11 | byte[] result = digest.digest(password.getBytes()); 12 | 13 | StringBuffer sb = new StringBuffer(); 14 | for (byte b : result) { 15 | int i = b & 0xff;// 将字节转为整数 16 | String hexString = Integer.toHexString(i);// 将整数转为16进制 17 | 18 | if (hexString.length() == 1) { 19 | hexString = "0" + hexString;// 如果长度等于1, 加0补位 20 | } 21 | 22 | sb.append(hexString); 23 | } 24 | 25 | System.out.println(sb.toString());//打印得到的md5 26 | 27 | } catch (NoSuchAlgorithmException e) { 28 | // 如果算法不存在的话,就会进入该方法中 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | 登录网站: http://www.cmd5.com/ 验证md5准确性 34 | 35 | 为避免暴力破解, 可以对算法加盐 36 | 37 | 什么是加盐? 38 | 39 | 比如以前我们只是把password进行md5加密, 现在可以给password加点盐,这个盐可以是一个固定的字符串,比如用户名username, 然后我们计算一下md5(username+password), 保存在服务器的数据库中, 即使这个md5泄露, 被人破解后也不是原始的密码, 一定程度上增加了安全性 40 | 41 | 目前市面上已经可以达到的解密水平 42 | ![](http://olg7c0d2n.bkt.clouddn.com/17-4-16/50834804-file_1492331802703_cf3.png) -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/华为手机无法打印日志解决办法.md: -------------------------------------------------------------------------------- 1 | # 华为手机Log.d无法打印日志的解决办法 2 | 3 | 1.进入拨号界面输入:*#*#2846579#*#* 4 | 2.依次选择 工程菜单---后台设置----LOG设置---LOG开关(或者AP日志) 点击打开 5 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/单例模式.md: -------------------------------------------------------------------------------- 1 | # 单例模式 2 | 3 | > 有时候,比如数据库的操作类,需要是单例模式. 4 | 5 | 基本步骤如下: 6 | 7 | 1.私有化构造方法 8 | 9 | 2.声明一个当前类的对象 10 | 11 | 3.提供一个静态方法,如果当前类的对象为空,创建一个新的 12 | 13 | 代码如下: 14 | 15 | public class BlackNumberDao { 16 | 17 | /** 18 | * 黑名单数据库帮助类 19 | */ 20 | private BlackNumberOpenHelper blackNumberOpenHelper; 21 | /** 22 | * 2.声明一个当前类的对象 23 | */ 24 | private static BlackNumberDao blackNumberDao; 25 | 26 | //需要设计一个单例模式 27 | //1, 私有化构造方法 28 | private BlackNumberDao(Context context){ 29 | blackNumberOpenHelper = new BlackNumberOpenHelper(context); 30 | } 31 | 32 | /** 33 | * 3.提供一个静态方法,如果当前类的对象为空,创建一个新的 34 | * @return 35 | */ 36 | public static BlackNumberDao getInstance(Context context){ 37 | if(blackNumberDao == null) { 38 | blackNumberDao = new BlackNumberDao(context); 39 | } 40 | return blackNumberDao; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/单元测试.md: -------------------------------------------------------------------------------- 1 | # 单元测试 2 | 3 | # 1. Android测试 4 | 5 | 使用AndroidJUnitRunner 6 | 7 | 1.需要在src/androidTest/java/com.xfhy.xx下面新建一个自己的测试类,比如ExampleInstrumentedTest 8 | 9 | 在里面写入代码 10 | 11 | /** 12 | * Created by xfhy on 2017/5/6. 13 | * 测试 14 | */ 15 | @RunWith(AndroidJUnit4.class) 16 | public class TestBlackNumberDao { 17 | 18 | @Test 19 | public void insert(){ 20 | BlackNumberDao dao = BlackNumberDao.getInstance(InstrumentationRegistry 21 | .getTargetContext()); 22 | dao.insert("110","1"); 23 | } 24 | 25 | } 26 | 27 | 2.之后,在需要测试的方法上写@Test,然后在方法的左侧,会出现下面的这个按钮. 28 | 29 | ![](http://olg7c0d2n.bkt.clouddn.com/17-5-6/38625506-file_1494076952538_18604.png) 30 | 31 | 3.点一下,就可以测试啦!成功~ 32 | 33 | 成功的时候是这样的 34 | 35 | ![](http://olg7c0d2n.bkt.clouddn.com/17-5-6/63913463-file_1494077031297_14b89.png) 36 | 37 | - **InstrumentationRegistry.getTargetContext()** 可以获取到用于测试的Context 38 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/双击返回键退出.md: -------------------------------------------------------------------------------- 1 | # 双击返回键退出 2 | 3 | //双击退出 4 | @Override 5 | public boolean onKeyDown(int keyCode, KeyEvent event) { 6 | 7 | //按下键是返回键 8 | if (keyCode == KeyEvent.KEYCODE_BACK) { 9 | if (!isExit) { 10 | Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show(); 11 | isExit = true; 12 | 13 | Timer timer = new Timer(); 14 | //定时器 如果2000毫秒之后没按,则重新设置为false 表示用户不想退出 15 | TimerTask timerTask = new TimerTask() { 16 | @Override 17 | public void run() { 18 | //还原状态 19 | isExit = false; 20 | } 21 | }; 22 | //2000毫秒之后再执行 23 | timer.schedule(timerTask, 2000); 24 | 25 | return true; 26 | } 27 | } 28 | 29 | return super.onKeyDown(keyCode, event); 30 | } -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/回调编写.md: -------------------------------------------------------------------------------- 1 | # 回调编写 2 | 3 | 1. 定义一个接口 4 | 2. 定义接口中未实现的业务逻辑方法 5 | 3. 传递一个实现了此接口的类的对象,一定实现了上诉接口未实现方法 6 | 4. 获取传递进来的对象,在合适的地方,做方法的调用 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/在组件中获取Application.md: -------------------------------------------------------------------------------- 1 | 首先项目是组件化了的,其次有一个library组件,用做基础组件. 2 | 然后在基础组件里面新建一个BaseApplication作为Application基类.然后在主工程里面新建一个XXApplication继承BaseApplication(记得在清单文件中注册),就可以啦. 3 | 4 | 我们在BaseApplication中的onCreate()中获取到了实例,那么即可在该library中获取Application了.当然,也可以在其他引入了基础组件的组件里面获取Application 5 | 6 | ```java 7 | public class BaseApplication extends Application{ 8 | 9 | private static BaseApplication mApplication; 10 | 11 | public static BaseApplication getInstance() { 12 | return mApplication; 13 | } 14 | 15 | @Override 16 | public void onCreate() { 17 | super.onCreate(); 18 | mApplication = this; 19 | } 20 | } 21 | ``` -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/屏幕高度+状态栏高度.md: -------------------------------------------------------------------------------- 1 | # Android 屏幕高度 状态栏高度 2 | 3 | # 一.获取屏幕高度 4 | 5 | WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); 6 | Display defaultDisplay = mWM.getDefaultDisplay(); 7 | DisplayMetrics displayMetrics = new DisplayMetrics(); 8 | defaultDisplay.getMetrics(displayMetrics); 9 | mScreenWidth = displayMetrics.widthPixels; //显示的绝对宽度(以像素为单位) 10 | mScreenHeight = displayMetrics.heightPixels; 11 | 12 | # 二.获取状态栏高度 13 | 14 | /** 15 | * 获取状态栏高度 16 | * @param activity 17 | * @return 高度 18 | */ 19 | public static int getStatusBarHeight(AppCompatActivity activity){ 20 | Rect rect = new Rect(); 21 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); 22 | return rect.top==0 ? 60 : rect.top; 23 | } 24 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/常见布局.md: -------------------------------------------------------------------------------- 1 | # 常见布局 2 | 3 | - CoordinatorLayout 4 | - DrawerLayout 抽屉布局 5 | - ConstraintLayout 拖拽的布局 6 | - LinearLayout 7 | - FrameLayout 8 | - RelativeLayout 9 | - GridLayout 格子布局 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/强制让字体不随着系统字体大小而变化.md: -------------------------------------------------------------------------------- 1 | # sp还是dp 2 | 3 | 众所周知,官方建议我们字体的单位使用sp,这样用户在“系统设置”中调整了系统字体大小的时候,我们app中的字体会随着系统字体的大小而改变。So,众猿机智的在布局文件中写下了以下代码 4 | ```xml 5 | 10 | ``` 11 | 当然上述TextView不会有什么问题,因为这货height是自适应的。但是很多情境下,例如ListView或者Recyclerview的item中,高度是固定的时候,sp就会有适配问题,例如 12 | ![](https://dn-mhke0kuv.qbox.me/6b257592a7c6fdc2f24f.png?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 13 | 14 | 解决方案: 15 | 在Application中重写onConfigurationChanged 强制字体不随着系统改变而改变(微信也是这么干的) 16 | ```java 17 | @Override 18 | public void onConfigurationChanged(Configuration newConfig) { 19 | if (newConfig.fontScale != 1)//非默认值 20 | getResources(); 21 | super.onConfigurationChanged(newConfig); 22 | } 23 | 24 | @Override 25 | public Resources getResources() { 26 | Resources res = super.getResources(); 27 | if (res.getConfiguration().fontScale != 1) {//非默认值 28 | Configuration newConfig = new Configuration(); 29 | newConfig.setToDefaults(); 30 | //设置默认 31 | res.updateConfiguration(newConfig, res.getDisplayMetrics()); 32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 33 | createConfigurationContext(newConfig); 34 | } else { 35 | res.updateConfiguration(newConfig, res.getDisplayMetrics()); 36 | } 37 | } 38 | return res; 39 | } 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/热修复原理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android学习笔记/杂乱的知识点/热修复原理.png -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/生成快捷方式.md: -------------------------------------------------------------------------------- 1 | # 生成快捷方式 2 | 3 | 1.查看源码 apps->Launcher3 4 | 看到清单文件中如下所示: 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 这告诉我们,想生成快捷方式,就需要发送广播到InstallShortcutReceiver. 16 | 而且需要权限. 17 | 18 | 2.下面是生成快捷方式的方法 19 | 20 | private void initShortCut() { 21 | // 从源码Launcher3 中查看 生成快捷方式 需要Action,图标,名称,需要打开的Intent,权限 22 | //1, 创建发送安装快捷方式的意图 23 | Intent installShortCutIntent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT"); 24 | //2, 封装图标 25 | installShortCutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, BitmapFactory.decodeResource 26 | (getResources(),R.mipmap.ic_launcher)); 27 | //3, 封装名称进去 28 | installShortCutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME,"手机卫士"); 29 | //4, 封装一个需要打开的Intent进去 打开九宫格界面 30 | Intent homeIntent = new Intent("com.xfhy.intent.action.HOME"); 31 | homeIntent.addCategory("android.intent.category.DEFAULT"); 32 | installShortCutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,homeIntent); 33 | 34 | //5, 发送广播 生成快捷方式 35 | sendBroadcast(installShortCutIntent); 36 | 37 | //6, 已生成快捷方式 需要生成SP,方便下一次判断是否已经生成了快捷方式 38 | // 如果不判断,快捷方式可以重复生成 39 | SpUtil.putBoolean(ConstantValue.INSTALL_SHORTCUT,true); 40 | } 41 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/监测Activity的生命周期事件.md: -------------------------------------------------------------------------------- 1 | # 监测Activity的生命周期事件 2 | 3 | 4 | 在applicatio中加入 this.registerActivityLifecycleCallbacks(this); -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/组件化开发注意事项.md: -------------------------------------------------------------------------------- 1 | # 组件化开发注意事项 2 | 3 | # 1, 组件里面不能用switch -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/给Android开发者的RxJava详解.md: -------------------------------------------------------------------------------- 1 | # 给Android开发者的RxJava详解 2 | 3 | > 本文只是本人在看原著时的笔记,想要看原文的小伙伴可以[点击进去这里](http://gank.io/post/560e15be2dca930e00da1083#toc_1)查看原文. 4 | 5 | ## RxJava的基本实现主要有三点 6 | 7 | ### Observer 8 | 9 | > 即观察者,它决定事件触发的时候将有怎样的行为. 10 | 11 | ### Observable 12 | 13 | > 即被观察者,它决定什么时候触发事件以及触发怎样的事件. 14 | 15 | ### Subscribe 16 | 17 | > 即订阅.创建了Observable和Observer之后,再用subscribe()方法将它们联结起来,整条链子就可以工作了. 18 | 19 | 放图(图片来自给Android开发者的RxJava详解) 20 | 21 | ![](http://ww3.sinaimg.cn/mw1024/52eb2279jw1f2rx4ay0hrg20ig08wk4q.gif) 22 | 23 | ## 线程控制(一) 24 | 25 | > 如果需要切换线程,就需要用到Scheduler(调度器) 26 | 27 | - Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。 28 | - Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。 29 | - Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。 30 | - Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。 31 | - 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。 32 | 33 | 有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。 * subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。 * observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。 34 | 35 | Observable.just(1, 2, 3, 4) 36 | .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程 37 | .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程 38 | .subscribe(new Action1() { 39 | @Override 40 | public void call(Integer number) { 41 | Log.d(tag, "number:" + number); 42 | } 43 | }); 44 | 45 | ## 线程控制(二) 46 | 47 | 换句话说,observeOn() 指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求,只要在每个想要切换线程的位置调用一次 observeOn() 即可。上代码: 48 | 49 | Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定 50 | .subscribeOn(Schedulers.io()) 51 | .observeOn(Schedulers.newThread()) 52 | .map(mapOperator) // 新线程,由 observeOn() 指定 53 | .observeOn(Schedulers.io()) 54 | .map(mapOperator2) // IO 线程,由 observeOn() 指定 55 | .observeOn(AndroidSchedulers.mainThread) 56 | .subscribe(subscriber); // Android 主线程,由 observeOn() 指定 57 | 58 | 如上,通过 observeOn() 的多次调用,程序实现了线程的多次切换。 59 | 60 | 不过,不同于 observeOn() , subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。 61 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/网络缓存.md: -------------------------------------------------------------------------------- 1 | # 网络缓存 2 | 3 | > 网络缓存作用:当用户第一次进入应用加载了很多东西,然后第二次进入应用时网络环境不佳,然后什么都不显示,用户就要等很久....其实可以这样,第一次进入时加载的东西( (key,value) -> (url,json) )缓存起来,第二次进入直接解析json内容,然后先暂时显示出来,满足用户的心里安慰. 4 | 5 | ## 1. 方式1: SharedPreferences 6 | ## 2. 方式2: 文件 7 | ## 3. 方式3: 数据库 8 | 9 | -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/解决Android Studio配置完Kotlin下载慢的问题.md: -------------------------------------------------------------------------------- 1 | # 解决Android Studio配置完Kotlin下载慢的问题 2 | 3 | 使用阿里云的国内镜像仓库地址,就可以快速的下载需要的文件 4 | 5 | 修改项目根目录下的文件 6 | 7 | build.gradle :buildscript { 8 | repositories { 9 | //加入下面这句 10 | maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'} 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | //加入下面这句 17 | maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'} 18 | } 19 | } 20 | 21 | 作者:DIABLOHL 22 | 链接:https://www.zhihu.com/question/37810416/answer/153168766 23 | 来源:知乎 -------------------------------------------------------------------------------- /Android/Android学习笔记/杂乱的知识点/锁屏事件监听.md: -------------------------------------------------------------------------------- 1 | # Android 锁屏事件监听 2 | 3 | > 有时候会去监听锁屏事件,方便我们处理一些事情. 4 | 5 | 屏幕的解锁和锁屏是比较频繁的事件,所以需要动态注册广播接收者. 6 | 比如,下面这个Service是用来监听锁屏,然后做进程清理的. 7 | 8 | /** 9 | * 监听系统是否锁屏的服务 当接收到系统锁屏的广播,清理内存 10 | */ 11 | public class LockScreenClearService extends Service { 12 | 13 | private static final String TAG = "LockScreenClearService"; 14 | private IntentFilter mIntentFilter; 15 | private ScreenOffReceiver mReceiver; 16 | 17 | public LockScreenClearService() { 18 | } 19 | 20 | @Override 21 | public IBinder onBind(Intent intent) { 22 | throw new UnsupportedOperationException("Not yet implemented"); 23 | } 24 | 25 | @Override 26 | public void onCreate() { 27 | //1, 定义锁屏的IntentFilter 28 | mIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 29 | //2, 定义锁屏广播接收者 30 | mReceiver = new ScreenOffReceiver(); 31 | //3, 注册广播接收者 32 | registerReceiver(mReceiver,mIntentFilter); 33 | 34 | super.onCreate(); 35 | } 36 | 37 | @Override 38 | public void onDestroy() { 39 | if (mReceiver != null) { 40 | unregisterReceiver(mReceiver); 41 | } 42 | super.onDestroy(); 43 | } 44 | 45 | class ScreenOffReceiver extends BroadcastReceiver { 46 | @Override 47 | public void onReceive(Context context, Intent intent) { 48 | if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){ 49 | //清理所有能清理的进程 50 | ProcessInfoProvider.killAllProcess(context); 51 | LogUtil.d(TAG,"清理所有进程完成"); 52 | } 53 | } 54 | } 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /Android/Android学习笔记/面试.md: -------------------------------------------------------------------------------- 1 | ##面试 2 | 3 | [TOC] 4 | 5 | #1.子线程其实可以更新UI 6 | 1.审计机制 在Activity还没完全显示的时候,是不会去检测子线程是否在更 7 | 新UI,但是可以在还没完全显示完Activity的时候更新UI,就能成功. 8 | 2.SurfaceView:多媒体视频播放,可以在子线程更新UI 9 | 3.Progress(进度)相关的控件:也可以在子线程中更新UI 10 | 11 | #2. aidl介绍 12 | >进程间通信(IPC) 使用技术:aidl 13 | 14 | ##aidl的应用场景 15 | 支付宝 非常有名 支付的方法 16 | 17 | #4. start方式开启服务和bindService方式开启区别 18 | 19 | ## start方式开启服务的特点(面试) 20 | 21 | >startService开启服务,服务就会在后台长期运行,知道用户手工停止,或者调用stopService()方法,服务才会被销毁 22 | 23 | ## bindService 方式开启服务的特点(面试) 24 | 25 | >当Activity销毁的时候服务也销毁,不求同时生但求同时死 26 | 27 | -------------------------------------------------------------------------------- /Android/Android高级/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android高级/.DS_Store -------------------------------------------------------------------------------- /Android/Android高级/1. Binder、AIDL、多进程/Android IPC机制 脑图.md: -------------------------------------------------------------------------------- 1 | 2 | [网页](https://mubu.com/doc/yHUg7qcbA0) 3 | 4 | 5 | ![image](6289F954C5504500B60BA47FF48C6042) -------------------------------------------------------------------------------- /Android/Android高级/1. Binder、AIDL、多进程/Android IPC机制.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### Binder连接池 4 | 5 | 起因: 当aidl比较多的时候,需要用到Binder连接池,为了共用一个Service.这个Service可兼容多个aidl 6 | 7 | ![image](8490C8561A0C429E8B0C5242CEE018D5) 8 | 9 | 原理: 我们需要减少Service的数量,将所有的AIDL放在同一个Service中去管理。每个业务模块创建自己的AIDL接口并实现 10 | 此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然 11 | 后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个 12 | Service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来 13 | 返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进行远程 14 | 方法调用了。由此可见,Binder连接池的主要作用就是将每个业务模块的Binder请求统一 15 | 转发到远程Service中去执行,从而避免了重复创建Service的过程. -------------------------------------------------------------------------------- /Android/Android高级/1. Binder、AIDL、多进程/Binder核心原理.md: -------------------------------------------------------------------------------- 1 | 2 | ## 一、什么是Binder 3 | 4 | - 安卓的IPC机制 5 | - Linux的驱动 /dev/binder 6 | - 安卓系统中的Binder类,实现了IBinder接口 7 | 8 | ## 二、为什么增加Binder机制 9 | 10 | > 安卓本身是一个linux系统,我们知道linux已经有一些进程通信方式,为什么安卓还需要单独新增呢? 11 | 12 | - 常用的通信方式有:Socket,消息队列,管道和共享内存. 13 | - 原因:主要是基于性能、稳定性和安全性几方面的考虑 14 | 15 | #### 性能方面 16 | 17 | - Socket:作为一款通用接口,起传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。 18 | - 消息队列和管道:采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。 19 | - 共享内存:虽然无需拷贝,但控制复杂,难以使用。 20 | - Binder:只需要一次数据拷贝,性能上仅次于共享内存。 21 | 22 | #### 稳定性方面 23 | 24 | #### 安全性方面 25 | 26 | uid 标识进程 27 | 28 | ## 三、Binder数据传输机制 29 | 30 | 一次拷贝 拷贝到内核区,存在映射关系,然后另一个进程就拿到数据了 31 | 32 | aidl 来实现的进程通信。 33 | 34 | 存在相同的aidl 35 | 36 | - aidl 生成出来的代码必须看懂 37 | - Proxy 发送数据,Stub 接收数据 38 | - asInterface : 先判断是否是同一进程,mRemote是服务端的代理。写到包里面去,发送。transact:绑定,挂起。(参数:调用哪个方法,0:双端通信) 39 | - 服务端:onTransact(); 校验。 -------------------------------------------------------------------------------- /Android/Android高级/1. IPC机制/Android IPC机制 脑图.md: -------------------------------------------------------------------------------- 1 | 2 | [网页](https://mubu.com/doc/yHUg7qcbA0) 3 | 4 | 5 | ![image](6289F954C5504500B60BA47FF48C6042) -------------------------------------------------------------------------------- /Android/Android高级/1. IPC机制/Android IPC机制.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### Binder连接池 4 | 5 | 起因: 当aidl比较多的时候,需要用到Binder连接池,为了共用一个Service.这个Service可兼容多个aidl 6 | 7 | ![image](8490C8561A0C429E8B0C5242CEE018D5) 8 | 9 | 原理: 我们需要减少Service的数量,将所有的AIDL放在同一个Service中去管理。每个业务模块创建自己的AIDL接口并实现 10 | 此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然 11 | 后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个 12 | Service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来 13 | 返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进行远程 14 | 方法调用了。由此可见,Binder连接池的主要作用就是将每个业务模块的Binder请求统一 15 | 转发到远程Service中去执行,从而避免了重复创建Service的过程. -------------------------------------------------------------------------------- /Android/Android高级/1. IPC机制/Binder核心原理.md: -------------------------------------------------------------------------------- 1 | 2 | ## 一、什么是Binder 3 | 4 | - 安卓的IPC机制 5 | - Linux的驱动 /dev/binder 6 | - 安卓系统中的Binder类,实现了IBinder接口 7 | 8 | ## 二、为什么增加Binder机制 9 | 10 | > 安卓本身是一个linux系统,我们知道linux已经有一些进程通信方式,为什么安卓还需要单独新增呢? 11 | 12 | - 常用的通信方式有:Socket,消息队列,管道和共享内存. 13 | - 原因:主要是基于性能、稳定性和安全性几方面的考虑 14 | 15 | #### 性能方面 16 | 17 | - Socket:作为一款通用接口,起传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。 18 | - 消息队列和管道:采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。 19 | - 共享内存:虽然无需拷贝,但控制复杂,难以使用。 20 | - Binder:只需要一次数据拷贝,性能上仅次于共享内存。 21 | 22 | #### 稳定性方面 23 | 24 | #### 安全性方面 25 | 26 | uid 标识进程 27 | 28 | ## 三、Binder数据传输机制 29 | 30 | 一次拷贝 拷贝到内核区,存在映射关系,然后另一个进程就拿到数据了 31 | 32 | aidl 来实现的进程通信。 33 | 34 | 存在相同的aidl 35 | 36 | - aidl 生成出来的代码必须看懂 37 | - Proxy 发送数据,Stub 接收数据 38 | - asInterface : 先判断是否是同一进程,mRemote是服务端的代理。写到包里面去,发送。transact:绑定,挂起。(参数:调用哪个方法,0:双端通信) 39 | - 服务端:onTransact(); 校验。 -------------------------------------------------------------------------------- /Android/Android高级/11. 刁钻问题汇总/把玩Android多进程.pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android高级/11. 刁钻问题汇总/把玩Android多进程.pdf.pdf -------------------------------------------------------------------------------- /Android/Android高级/13. RxJava/一句话总结RxJava.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | RxJava 其实就是提供一套异步编程的 API,这套 API 是基于观察者模式的,而且是链式调用的,所以使用 RxJava 编写的代码的逻辑会非常简洁。 而且还可以切换线程 -------------------------------------------------------------------------------- /Android/Android高级/14. Glide/xfhy Glide(二)缓存机制探索.md: -------------------------------------------------------------------------------- 1 | 2 | 前面分析了一篇Glide主流程概述,但是总觉得缺少点什么.没有对其Glide的缓存机制进行介绍,Glide的缓存十分强大,使用也非常简单,然后封装得极好.好的缓存机制可以让用户少花流量,且能很快速得从缓存中读取到缓存然后展示出来. 3 | 4 | ## 一.Glide缓存机制简介 5 | 6 | 众所周知,Glide有三级缓存.分别是 7 | 8 | - 内存缓存,LruCache和弱引用缓存 9 | - 磁盘缓存,DiskLruCache 10 | - 网络缓存,感觉不怎么算.. 11 | 12 | ## 二.缓存Key 13 | ## 三.内存缓存 14 | ## 四.磁盘缓存 15 | -------------------------------------------------------------------------------- /Android/Android高级/16. Gradle 插件基础/Gradle系列(四) Gradle插件.md: -------------------------------------------------------------------------------- 1 | 2 | ## 1. 前言 3 | 4 | 依赖`apply plugin: 'com.android.application'`就是依赖了安卓的应用程序插件.然后这个插件里面有android扩展,在[官方文档](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.AppExtension.html)里面有详细描述.但是,有时候不得不自己写一个插件,方便与业务开展.比如我觉得美团的热修复,在每个方法前面插逻辑的话,肯定得插桩,插桩就得自己写插件.方便快捷.Gradle+ASM可以插桩.有兴趣的可以去了解. 5 | 6 | demo地址: https://github.com/xfhy/GradleStudy 7 | 8 | ## 2. 简单插件 9 | 10 | 新建一个简单的项目,然后创建一个buildSrc这个名字的module,这个module的名称必须为buildSrc.因为我们创建的这个module是AS专门用来写插件的,会自动参与编译.创建好之后删除Android那一堆东西,什么java代码,res,清单文件等.只剩下build.gradle和.gitignore 11 | 12 | ![QQleEj.png](https://s2.ax1x.com/2019/12/03/QQleEj.png) 13 | 14 | 把build.gradle文件内容改成 15 | ```gradle 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | apply { 21 | plugin 'groovy' 22 | plugin 'java-gradle-plugin' 23 | } 24 | dependencies { 25 | implementation gradleApi() 26 | implementation localGroovy() 27 | implementation "commons-io:commons-io:2.6" 28 | } 29 | ``` 30 | 31 | 然后在main下面创建文件夹groovy,sync一下.没啥问题的话,应该能编译过.然后在groovy文件夹下面创建包名`com.xfhy.plugin`,然后创建一个插件,名字叫CustomPlugin.groovy 32 | 33 | ```groovy 34 | package com.xfhy.plugin 35 | 36 | import org.gradle.api.Plugin 37 | import org.gradle.api.Project 38 | 39 | class CustomPlugin implements Plugin { 40 | @Override 41 | void apply(Project project) { 42 | project.task('showCustomPlugin') { 43 | doLast { 44 | println('hello world plugin!') 45 | } 46 | } 47 | } 48 | } 49 | ``` 50 | 51 | 我在这里声明了一个CustomPlugin插件,然后里面创建了一个task名字叫showCustomPlugin,showCustomPlugin插件就只是简单输出一句话. 然后在app的build.gradle里面引入这个插件 52 | 53 | ```gradle 54 | import com.xfhy.plugin.CustomPlugin 55 | apply plugin: CustomPlugin 56 | ``` 57 | 58 | 然后就可以在命令行输入`gradlew showCustomPlugin`执行这个插件.然后就可以在命令行看到输出了. 59 | -------------------------------------------------------------------------------- /Android/Android高级/20. jni/NDK学习资料.md: -------------------------------------------------------------------------------- 1 | 2 | https://github.com/JsonChao/Awesome-Android-NDK 3 | -------------------------------------------------------------------------------- /Android/Android高级/5. Activity 难点/setResult() 的调用时机.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://www.cnblogs.com/shaweng/p/3875825.html 2 | 3 |   今天遇到这样一个问题,我在 Activity-**A** 中用 startActivityForResult() 方法启动了 Activity**-B**,并且在 **B** 中通过 setResult**()** 方法给 **A** 返回值,由于某些原因不能在 setResult() 之后立刻调用 finish() 函数,只能通过用户按 Back 键自己退出到 **A**。按理说从 **B** 退出回到 Aactivity-**A** 过程中,**A** 中的 onActivityResult**() **应该被调用, 可是通过 log 发现,整个操作过程中 onActivityResult() 始终没有被调用。 前后研究了半天才发现 是 setResult() 的调用时机不对造成的,因为在我是在 **B** 的 onStop() 函数中调用 setResult() 函数的,这个时候的 seResult 是没有任何意义的,因为已经错过了 **A** onActivityResult() 的调用时机。 4 | 5 |   因为在 **B **退回** A** 过程中,执行过程是 6 | 7 |   B---onPause 8 |   A---onActivityResult 9 |   A---onRestart 10 |   A---onStart 11 |   A---onResume 12 |   B---onStop 13 |   B---onDestroy 14 | 15 |   从上面过程可以看出,首先是 **B** 处于 Pause 状态,然后等待 **A** 执行onRestart——> onStart ——〉onResume,然后才是 B 的 onSstop——>onSdestroy,而 **A** 的 onActivityResult() 需要在 **B** 的 onPause 之后,**A** 的 onRestart 之前这中间调用,所以 **B** 中的 setResult() 函数应该放在 **B** 的 onPause 之前调用。 16 | 17 | 另外我试验了一下,如果把 setResult() 放在 **B** 的 onPause() 里面调用,结果仍然是无效的。 18 | 19 | 那么 setResult() 应该在什么时候调用呢?从源码可以看出,Activity 返回 result 是在被 finish 的时候,也就是说调用 setResult() 方法必须在 finish() 之前。所以在 onPause、onStop、onDestroy 方法中调用 setResult() 也有可能不会返回成功,因为这些方法调用不一定是在 finish 之前的,当然在 onCreate() 就调用 setResult 肯定是在 finish 之前的,但是又不满足业务需要。 20 | 21 | 实际使用场景有两个: 22 | 23 | (1)按 BACK 键从一个 Activity 退出来的,一按 BACK,android 就会自动调用 Activity 的 finish() 方法, 24 | 25 |        方法:重写 onBackPressed() 方法,捕获 BACK 事件,捕获到之后先 setResult。代码: 26 | 27 | [?](#) 28 | 29 | | 1234567 | `@Override``public` `void` `onBackPressed()``{``Log.i(TAG,` `"onBackPressed"``);``setResult(Const.LIVE_OK);``super``.onBackPressed();``}` | 30 | 31 | (2)按**点击事件**中显式的调用 finish() 32 | 33 | [?](#) 34 | 35 | | 12 | `setResult(RESULT_OK);``finish();` | 36 | 37 | 执行过程为: 38 | 39 |   B---onBackPressed 40 |   B---finish 41 |   B---onPause 42 |   A---onActivityResult 43 |   A---onRestart 44 |   A---onStart 45 |   A---onResume 46 |   B---onStop 47 |   B---onDestroy -------------------------------------------------------------------------------- /Android/Android高级/6. Service 难点/Service知识点.md: -------------------------------------------------------------------------------- 1 | 2 | #### startService 生命周期 3 | 4 | ``` 5 | onCreate 6 | onStartCommand 7 | ``` 8 | 9 | #### bindService 生命周期 10 | 11 | ``` 12 | onCreate 13 | onBind 14 | ``` 15 | 16 | #### onStartCommand 17 | 18 | **START_NOT_STICKY**:表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service,如果想重新实例化该Service,就必须重新调用startService来启动。 19 | 20 | 使用场景:表示当Service在执行工作中被中断几次无关紧要或者对Android内存紧张的情况下需要被杀掉且不会立即重新创建这种行为也可接受的话,这是可以在onStartCommand返回值中设置该值。如在Service中定时从服务器中获取最新数据 21 | 22 | **START_STICKY**:表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,这时onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。 23 | 24 | 使用场景:如果你的Service可以在任意时刻运行或结束都没什么问题,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY,比如一个用来播放背景音乐功能的Service就适合返回该值。 25 | 26 | **START_REDELIVER_INTENT**:表示Service运行的进程被Android系统强制杀掉之后,与返回START_STICKY的情况类似,Android系统会将再次重新创建该Service,并执行onStartCommand回调方法,但是不同的是,Android系统会再次将Service在被杀掉之前最后一次传入onStartCommand方法中的Intent再次保留下来并再次传入到重新创建后的Service的onStartCommand方法中,这样我们就能读取到intent参数。 -------------------------------------------------------------------------------- /Android/Android高级/7. BroadCastReceiver/android 静态广播和动态广播的区别和用法.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://blog.csdn.net/u011897782/article/details/81119231 2 | 3 | 一、什么是广播 4 | 5 | BroadcastReceiver 是 android 系统的四大组件之一,本质上就是一个全局的监听器,用于监听系统全局的广播消息,可以方便的实现系统中不同组件之间的通信。 6 | 7 | 程序可以通过调用 context 的 sendBroadcast() 方法来启动指定的 BroadcastReceiver. 8 | 9 | 二、广播的生命周期 10 | 11 | BroadcastReceiver 生命周期只有十秒左右,如果在 onReceive() 内做超过十秒的事情,就会报错。所以广播中不要执行耗时操作,可以考虑启动一个 Service 来完成操作。 12 | 13 | 三、注册 BroadcastReceiver 14 | 15 | 广播分为两种:静态注册和动态注册 16 | 17 | 1\. 静态注册 18 | 19 | AndroidManifest.xml 文件中配置 20 | 21 | 特点:常驻形广播,程序推出后,广播依然存在。 22 | 23 | 示例:创建广播,新建一个类,继承自 BroadcastReceiver, 并重写 onReceive() 方法,在 manifest 文件中注册该广播,在发送广播。 24 | 25 | ![](https://img-blog.csdn.net/20180719172655939?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE4OTc3ODI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 26 | 27 | ![](https://img-blog.csdn.net/20180719172709261?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE4OTc3ODI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 28 | 29 | 2\. 动态注册 30 | 31 | 代码中动态指定广播地址并注册 32 | 33 | 特点:非常驻型,广播会跟随程序的生命周期的结束而结束。 34 | 35 | 示例:新建内部类,继承 BroadcastReceiver, 并重写 onReceive() 方法,在 onStart()中注册广播,在 onStop() 中解除注册广播,在发送广播 36 | 37 | ![](https://img-blog.csdn.net/20180719172957268?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE4OTc3ODI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 38 | 39 | ![](https://img-blog.csdn.net/20180719173011628?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTE4OTc3ODI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) -------------------------------------------------------------------------------- /Android/Android高级/7. BroadCastReceiver/广播的一些基本操作.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 兼容 5 | Android 8.0对隐式广播做了限制 6 | 7 | 1. 能动态注册,就不静态注册 8 | 2. 如果一定要静态注册, 发送的时候指定包名,即发送显式广播 9 | 10 | 11 | -------------------------------------------------------------------------------- /Android/Android高级/RecyclerView/RecyclerView 使用.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### 1. 给RecyclerView的item添加点击效果 4 | 5 | - 方式1:`android:foreground="?android:attr/selectableItemBackground"` 6 | - 方式2: 7 | 8 | ``` 9 | 10 | 11 | 12 | 13 | 14 | ``` 15 | -------------------------------------------------------------------------------- /Android/Android高级/RecyclerView/RecyclerView 常用小技巧.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### 1. 给RecyclerView的item添加点击效果 4 | 5 | - 方式1:`android:foreground="?android:attr/selectableItemBackground"` 6 | - 方式2: 7 | 8 | ``` 9 | 10 | 11 | 12 | 13 | 14 | ``` 15 | 16 | #### 2. 删除滑动到最后屏幕边缘的辉光 17 | 18 | `android:overScrollMode="never"` 19 | 20 | never表示删除listView,viewpager,scrollview等滑动到最后屏幕边缘的辉光 21 | -------------------------------------------------------------------------------- /Android/Android高级/RecyclerView/RecyclerView和ScrollView的滑动冲突.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1. 不用NestedScrollView,只要设RecyclerView.setNestedScrollingEnable()也是能解决问题的 4 | 2. NestedScrollView,用他替代ScrollView,并且不用自定义RecyclerView等列表控件来解决滑动冲突。因为他的内部已经帮我们解决了子View的滑动冲突。 NestedScrollView在多种滑动情景下处理的很好,比如同时有横向和竖向的滑动的时候。 -------------------------------------------------------------------------------- /Android/Android高级/组件化/基你太美/utf-8' '0. AucFrame 之简介及学习.pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android高级/组件化/基你太美/utf-8' '0. AucFrame 之简介及学习.pdf.pdf -------------------------------------------------------------------------------- /Android/Android高级/组件化/基你太美/utf-8' '1. AucFrame 之让你的 Gradle 更智能.pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android高级/组件化/基你太美/utf-8' '1. AucFrame 之让你的 Gradle 更智能.pdf.pdf -------------------------------------------------------------------------------- /Android/Android高级/组件化/基你太美/utf-8' '2. AucFrame 之统一管理 Gradle.pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android高级/组件化/基你太美/utf-8' '2. AucFrame 之统一管理 Gradle.pdf.pdf -------------------------------------------------------------------------------- /Android/Android高级/组件化/基你太美/utf-8' 'AucFrame.pdf.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/Android高级/组件化/基你太美/utf-8' 'AucFrame.pdf.pdf -------------------------------------------------------------------------------- /Android/Android高级/组件化/基你太美/基你太美 密码.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 密码是:aucFrame 4 | 5 | -------------------------------------------------------------------------------- /Android/JNI/1. NDK和JNI基本概念.md: -------------------------------------------------------------------------------- 1 | 2 | #### NDK是什么 3 | 4 | 原生开发工具包 (NDK) 是一组可让您在 Android 应用中利用 C 和 C++ 代码的工具。 可用以从您自己的源代码构建,或者利用现有的预构建库 5 | 6 | **NDK使用场景** 7 | 8 | > NDK会不可避免的增加开发过程的复杂性,通常是不建议使用的. 9 | 10 | - 从设备获取卓越性能以用于计算密集型应用,例如游戏或物理模拟。 11 | - 重复使用您自己或其他开发者的 C 或 C++ 库。 12 | 13 | 14 | #### JNI 15 | 16 | 从设备获取卓越性能以用于计算密集型应用,例如游戏或物理模拟。 17 | 重复使用您自己或其他开发者的 C 或 C++ 库。 18 | 19 | 20 | ![](http://upload-images.jianshu.io/upload_images/944365-6607e9321d3cbddd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -------------------------------------------------------------------------------- /Android/Material Design/12个MD控件.md: -------------------------------------------------------------------------------- 1 | # 12个MD控件 2 | 3 | > Material Design 4 | 5 | > 详细介绍: 6 | http://blog.csdn.net/hebin320320/article/details/51461611 7 | 8 | - CoordinatorLayout 9 | - AppBarLayout 10 | - ToolBar 11 | - DrawerLayout 12 | - NavigationView 13 | - CardView 14 | - AutoScrollViewPager 15 | - CollapsingToolbarLayout 16 | - TabLayout 17 | - TextInputLayout 18 | - FloatingActionButton 19 | - Snackbar -------------------------------------------------------------------------------- /Android/Material Design/Material Design.md: -------------------------------------------------------------------------------- 1 | 脑图展示 2 | 3 | ![](https://mmbiz.qpic.cn/mmbiz_png/jE32KtUXy6FZfDV7CO21g6UcwKhzCLfBVRB6viaB6nLTPYiaSnoianicYUtUR98iadyA6TMycWOamxaksiabjVE3B4Rg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 4 | 5 | > AndroidX了解一下:简单地说就是新的库可以在不同的Android版本上使用。比如之前我们如果使用support为27.1.1的相关依赖库时。可能需要所有相关的support 库都为27.1.1。如果其中有bug的话,可能需要所有的都去升级,存在一个绑定关系,而且正式版的发布周期也很长。 6 | 通过AndroidX,我们可以看到实时实现的特性和bug修复。升级个别依赖,不需要对使用的所有其他库进行更新。这就和我们使用Github上的开源库一样的,出了问题,我们可以提出bug和意见。作者修复后,发布新版本,我们就可以直接替换使用了。更加的透明便捷。**官方博客中有说道,为了给开发者一定迁移的时间,所以28.0.0的稳定版本还是采用android.support。但是所有后续的功能版本都将采用androidx。** 7 | 8 | #### 一、初始化配置 9 | 10 | Step 1: 打开工程目录下的build.gradle文件,并添加maven引用 11 | ``` 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | // 1.添加Google Maven地址 17 | maven { 18 | url "https://maven.google.com" 19 | } 20 | } 21 | } 22 | ``` 23 | Step 2: 修改编译版本 24 | ``` 25 | // 2.修改编译版本为 android - P 26 | compileSdkVersion 'android-P' 27 | ``` 28 | 29 | Step 3: 移除项目工程中依赖的v7包以及添加material依赖 30 | ``` 31 | dependencies { 32 | // 3.移除项目工程中依赖的v7包 33 | implementation fileTree(dir: 'libs', include: ['*.jar']) 34 | testImplementation 'junit:junit:4.12' 35 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 36 | implementation 'com.android.support.constraint:constraint-layout:1.1.0' 37 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 38 | // 4.添加material依赖 39 | implementation 'com.google.android.material:material:1.0.0' 40 | } 41 | ``` 42 | 当然,你可以使用com.android.support:design:28.0.0-alpha1,但是主要注意的是design包和material二者只能选一。 43 | 44 | Step 4: 使用:`androidx.appcompat.app.AppCompatActivity` 45 | 46 | 注意:使用的是androidx。 47 | ``` 48 | import androidx.appcompat.app.AppCompatActivity; 49 | public class MainActivity extends AppCompatActivity { 50 | ``` 51 | 同步一下,运行一波,虽然毛也没。。。好歹不报错~ 52 | 53 | 54 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView item点击水波纹效果.md: -------------------------------------------------------------------------------- 1 | 哇,相见恨晚,其实只需要在RecyclerView的itemView的最外层布局加一句 2 | android:foreground="?android:attr/selectableItemBackground" 3 | 4 | 在这里意思是指定有界的波纹 5 | 6 | 这里是API 21以上效果是比较好的,虽然API 21以下也能用,只是效果没有那么好看. -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView 官方分割线.md: -------------------------------------------------------------------------------- 1 | # DividerItemDecoration 官方的分割线 2 | 3 | > 今天忽然看到一个好东西,给大家分享一下.在API 25之后,Google添加了一个DividerItemDecoration用作RecyclerView的分割线,目前只支持LinearLayoutManager,垂直和水平都是支持的. 4 | 5 | 用法: 6 | 7 | mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), 8 | mLayoutManager.getOrientation()); 9 | recyclerView.addItemDecoration(mDividerItemDecoration); 10 | 11 | 12 | 简单吧,哈哈,官方的东西就是简单好用啊.感谢Google. 13 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.0" 6 | defaultConfig { 7 | applicationId "com.feiyang.complexlistlayout" 8 | minSdkVersion 17 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:26.0.0-alpha1' 28 | testCompile 'junit:junit:4.12' 29 | compile 'com.android.support:recyclerview-v7:26.0.0-alpha1' 30 | compile 'com.github.bumptech.glide:glide:4.0.0' 31 | } 32 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\AndroidSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/androidTest/java/com/feiyang/complexlistlayout/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.feiyang.complexlistlayout", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/adapter/SectionedSpanSizeLookup.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.adapter; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | 5 | /** 6 | * package: com.easyandroid.sectionadapter.adapter.SectionedSpanSizeLookup 7 | * author: gyc 8 | * description:分组每行显示数量的管理类 9 | * time: create at 2017/7/7 23:19 10 | */ 11 | 12 | public class SectionedSpanSizeLookup extends GridLayoutManager.SpanSizeLookup{ 13 | 14 | protected SectionedRecyclerViewAdapter adapter = null; 15 | protected GridLayoutManager layoutManager = null; 16 | 17 | public SectionedSpanSizeLookup(SectionedRecyclerViewAdapter adapter, GridLayoutManager layoutManager) { 18 | this.adapter = adapter; 19 | this.layoutManager = layoutManager; 20 | } 21 | 22 | @Override 23 | public int getSpanSize(int position) { 24 | if (adapter.hasHeader()) {//列表顶部有header 25 | if (position == 0) { 26 | return layoutManager.getSpanCount(); 27 | } else if (position + 1 < adapter.getItemCount()) { 28 | if (adapter.isSectionHeaderPosition(position -1) || adapter.isSectionFooterPosition(position -1)) { 29 | return layoutManager.getSpanCount(); 30 | } else { 31 | return 1; 32 | } 33 | } else { 34 | return layoutManager.getSpanCount(); 35 | } 36 | } else {//列表顶部没有header 37 | if (position + 1 < adapter.getItemCount()) { 38 | if (adapter.isSectionHeaderPosition(position) || adapter.isSectionFooterPosition(position)) { 39 | return layoutManager.getSpanCount(); 40 | } else { 41 | return 1; 42 | } 43 | } else { 44 | return layoutManager.getSpanCount(); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/holder/EmptyViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.holder; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * package: com.easyandroid.sectionadapter.holder.EmptyViewHolder 8 | * author: gyc 9 | * description:空布局 10 | * time: create at 2017/7/11 20:40 11 | */ 12 | 13 | public class EmptyViewHolder extends RecyclerView.ViewHolder { 14 | public EmptyViewHolder(View itemView) { 15 | super(itemView); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/holder/FooterHolder.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.holder; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.feiyang.complexlistlayout.R; 8 | 9 | 10 | /** 11 | * package: com.easyandroid.sectionadapter.holder.FooterHolder 12 | * author: gyc 13 | * description:上拉加载的footer 14 | * time: create at 2017/7/7 20:50 15 | */ 16 | 17 | public class FooterHolder extends RecyclerView.ViewHolder { 18 | public TextView tvFooter; 19 | 20 | public FooterHolder(View itemView) { 21 | super(itemView); 22 | initView(); 23 | } 24 | 25 | private void initView() { 26 | tvFooter = (TextView) itemView.findViewById(R.id.tv_footer); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/holder/TestSectionBodyHolder.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.holder; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | import android.widget.ImageView; 6 | import android.widget.LinearLayout; 7 | 8 | import com.feiyang.complexlistlayout.R; 9 | 10 | 11 | /** 12 | * package: com.easyandroid.sectionadapter.holder.TestSectionBodyHolder 13 | * author: gyc 14 | * description:SectionBody的holder 15 | * time: create at 2017/7/8 3:00 16 | */ 17 | 18 | public class TestSectionBodyHolder extends RecyclerView.ViewHolder{ 19 | 20 | public LinearLayout llRoot; 21 | public ImageView imgEvaluate; 22 | 23 | public TestSectionBodyHolder(View itemView) { 24 | super(itemView); 25 | initView(); 26 | } 27 | 28 | private void initView() { 29 | llRoot = (LinearLayout) itemView.findViewById(R.id.ll_root); 30 | imgEvaluate = (ImageView) itemView.findViewById(R.id.img_evaluate); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/holder/TestSectionFooterHolder.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.holder; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | import android.widget.ImageView; 6 | import android.widget.LinearLayout; 7 | import android.widget.TextView; 8 | 9 | import com.feiyang.complexlistlayout.R; 10 | 11 | 12 | /** 13 | * package: com.easyandroid.sectionadapter.holder.TestSectionFooterHolder 14 | * author: gyc 15 | * description:SectionFooter的holder 16 | * time: create at 2017/7/8 3:01 17 | */ 18 | 19 | public class TestSectionFooterHolder extends RecyclerView.ViewHolder{ 20 | 21 | public TextView tvLookNum,tvLikeNum, tvEvaluateNum; 22 | public LinearLayout llZan, llNum; 23 | public ImageView imgZan; 24 | 25 | public TestSectionFooterHolder(View itemView) { 26 | super(itemView); 27 | initView(); 28 | } 29 | 30 | private void initView() { 31 | tvLookNum = (TextView) itemView.findViewById(R.id.tv_look_num); 32 | llNum = (LinearLayout) itemView.findViewById(R.id.ll_evaluate); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/holder/TestSectionHeaderHolder.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.holder; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | import android.widget.ImageView; 6 | import android.widget.TextView; 7 | 8 | import com.feiyang.complexlistlayout.R; 9 | 10 | 11 | /** 12 | * package: com.easyandroid.sectionadapter.holder.TestSectionHeaderHolder 13 | * author: gyc 14 | * description:SectionHeader的holder 15 | * time: create at 2017/7/8 3:01 16 | */ 17 | 18 | public class TestSectionHeaderHolder extends RecyclerView.ViewHolder { 19 | public TextView tvNike, tvEvaluate, tvDate; 20 | public ImageView imgHead; 21 | 22 | public TestSectionHeaderHolder(View itemView) { 23 | super(itemView); 24 | initView(); 25 | } 26 | 27 | private void initView() { 28 | tvNike = (TextView) itemView.findViewById(R.id.tv_nike_name); 29 | tvEvaluate = (TextView) itemView.findViewById(R.id.tv_evaluate); 30 | tvDate = (TextView) itemView.findViewById(R.id.tv_date); 31 | imgHead = (ImageView) itemView.findViewById(R.id.img_head); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/holder/TypeAbstractViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.holder; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * package: com.easyandroid.sectionadapter.holder.TypeAbstractViewHolder 8 | * author: gyc 9 | * description: 10 | * time: create at 2017/8/3 22:21 11 | */ 12 | 13 | public abstract class TypeAbstractViewHolder extends RecyclerView.ViewHolder { 14 | 15 | public TypeAbstractViewHolder(View itemView) { 16 | super(itemView); 17 | } 18 | 19 | public abstract void bindHolder(T entity); 20 | } 21 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/java/com/feiyang/complexlistlayout/util/DeviceInforUtils.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout.util; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.Display; 6 | import android.view.WindowManager; 7 | 8 | import static android.content.Context.WINDOW_SERVICE; 9 | 10 | /** 11 | * description:设备信息(比如屏幕高度,宽度那些) 12 | * author feiyang 13 | * create at 2017/8/7 19:06 14 | */ 15 | public class DeviceInforUtils { 16 | 17 | /** 18 | * 获取屏幕信息 宽度,高度 19 | * @param context 20 | * @return 21 | */ 22 | public static DisplayMetrics getScreenInfor(Context context){ 23 | WindowManager windowManager = (WindowManager) context.getSystemService(WINDOW_SERVICE); 24 | Display defaultDisplay = windowManager.getDefaultDisplay(); 25 | DisplayMetrics displayMetrics = new DisplayMetrics(); 26 | defaultDisplay.getMetrics(displayMetrics); 27 | return displayMetrics; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/layout/item_section_body.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/layout/item_section_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 18 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/layout/item_section_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 26 | 27 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/layout/layout_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 12 | 21 | 22 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | 8 | #FAFAFA 9 | #AAAAAA 10 | 11 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12sp 4 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SectionRecyclerViewAdapter 3 | 浏览 %1$s 人 4 | 5 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/app/src/test/java/com/feiyang/complexlistlayout/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.feiyang.complexlistlayout; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/ComplexListLayout/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView万能分组/使用方法.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/RecyclerView/RecyclerView万能分组/使用方法.md -------------------------------------------------------------------------------- /Android/RecyclerView/RecyclerView禁止滚动.md: -------------------------------------------------------------------------------- 1 | 1, LinearLayoutManager不能多个RecyclerView公用 2 | 3 | 2,代码如下: 4 | 5 | LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(mContext) { 6 | @Override 7 | public boolean canScrollVertically() { 8 | return false; 9 | } 10 | }; 11 | recyclerView.setLayoutManager(mLinearLayoutManager); -------------------------------------------------------------------------------- /Android/RecyclerView/去除RecyclerView滑动边缘阴影效果.md: -------------------------------------------------------------------------------- 1 | 设置滑动到边缘时无效果模式: 2 | 3 | android:overScrollMode="never" 4 | 设置不显示滚动条: 5 | 6 | android:scrollbars="none" 7 | 完整属性: 8 | 9 | -------------------------------------------------------------------------------- /Android/kotlin/Java与Kotlin兼容问题.md: -------------------------------------------------------------------------------- 1 | 2 | ### 1. Java调用Kotlin文件方法或者属性 3 | 4 | BasicDataType.kt最终会编译成静态的属性或者方法 5 | 6 | ``` 7 | # BasicDataType.kt 8 | val str = "1" 9 | val age = 23 10 | 11 | # Test.java 12 | //需要使用类名+kt的方法,访问 有点像静态的 13 | System.out.println(BasicDataTypeKt.getAge()); 14 | ``` 15 | 16 | ### 2. object 17 | 18 | ``` 19 | object ObjectTest { 20 | //这里可以加入一个@JvmStatic注解,然后在Java中就可以直接类名.这个方法名 进行调用 21 | fun sayMessage(msg: String) { 22 | println(msg) 23 | } 24 | } 25 | 26 | java中调用 27 | ObjectTest.INSTANCE.sayMessage(""); 28 | 29 | ``` 30 | 31 | ### 3. class 32 | 33 | ``` 34 | Test::class.java 35 | ``` 36 | 37 | ### 4. val不能为null 38 | 39 | 当java返回的数据赋值给kotlin变量时,不确定是否为null,这时使用可空类型 -------------------------------------------------------------------------------- /Android/kotlin/Kotlin中的类.md: -------------------------------------------------------------------------------- 1 | # 类 2 | 3 | ## 定义一个类 4 | 5 | 如果你想定义一个类,你只需要使用 class 关键字。 6 | 7 | class MainActivity{ 8 | } 9 | 10 | 它有一个默认唯一的构造器。我们会在以后的课程中学习在特殊的情况下创建其它 11 | 额外的构造器,但是请记住大部分情况下你只需要这个默认的构造器。你只需要在 12 | 类名后面写上它的参数。如果这个类没有任何内容可以省略大括号: 13 | class Person(name: String, surname: String) 14 | 那么构造函数的函数体在哪呢?你可以写在 init 块中: 15 | 16 | class Person(name: String, surname: String) { 17 | init{ 18 | ... 19 | } 20 | } 21 | 22 | ## 类继承 23 | 24 | 默认任何类都是基础继承自 Any (与java中的 Object 类似),但是我们可以继 25 | 承其它类。所有的类默认都是不可继承的(final),所以我们只能继承那些明确声 26 | 明 open 或者 abstract 的类: 27 | 28 | open class Animal(name: String) 29 | class Person(name: String, surname: String) : Animal(name) 30 | 31 | ## 函数 32 | 33 | 函数(我们Java中的方法)可以使用 fun 关键字就可以定义: 34 | 35 | fun onCreate(savedInstanceState: Bundle?) { 36 | } 37 | 38 | 如果你没有指定它的返回值,它就会返回 Unit ,与Java中的 void 类似,但 39 | 是 Unit 是一个真正的对象。你当然也可以指定任何其它的返回类型: 40 | 41 | fun add(x: Int, y: Int) : Int { 42 | return x + y 43 | } 44 | 45 | 小提示:**分号不是必须的** 46 | 就想你在上面的例子中看到的那样,我在每句的最后没有使用分号。当然 47 | 你也可以使用分号,分号不是必须的,而且不使用分号是一个不错的实 48 | 践。当你这么做了,你会发现这节约了你很多时间。 49 | 50 | 然而如果返回的结果可以使用一个表达式计算出来,你可以不使用括号而是使用等 51 | 号:`fun add(x: Int,y: Int) : Int = x + y` 52 | 53 | ## 构造方法和函数参数 54 | Kotlin中的参数与Java中有些不同。如你所见,我们先写参数的名字再写它的类 55 | 型: 56 | 57 | fun add(x: Int, y: Int) : Int { 58 | return x + y 59 | } 60 | 61 | 我们可以给参数指定一个默认值使得它们变得可选,这是非常有帮助的。这里有一 62 | 个例子,在Activity中创建了一个函数用来toast一段信息: 63 | 64 | fun toast(message: String, length: Int = Toast.LENGTH_SHORT) { 65 | Toast.makeText(this, message, length).show() 66 | } 67 | 68 | 如你所见,第二个参数(length)指定了一个默认值。这意味着你调用的时候可以 69 | 传入第二个值或者不传,这样可以避免你需要的重载函数: 70 | 71 | toast("Hello") 72 | toast("Hello", Toast.LENGTH_LONG) 73 | 74 | 这个与下面的Java代码是一样的: 75 | 76 | void toast(String message){ 77 | } 78 | void toast(String message, int length){ 79 | Toast.makeText(this, message, length).show(); 80 | } 81 | 82 | 这跟你想象的一样复杂。再看看这个例子: 83 | 84 | toast(message = "Hello", length = Toast.LENGTH_SHORT) -------------------------------------------------------------------------------- /Android/kotlin/Kotlin的扩展库.md: -------------------------------------------------------------------------------- 1 | 2 | kotlin引入协程 3 | ``` 4 | // 👇 依赖协程核心库 5 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.1" 6 | // 👇 依赖当前平台所对应的平台库 7 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1" 8 | ``` 9 | 10 | ### 1. 协程基本概念 11 | 12 | - 通过提升CPU利用率,减少线程切换,进而提升程序运行效率 13 | - 可控制性:协程能做到可被控制的发起子任务 14 | - 轻量级:协程非常小,占用资源比线程还少 15 | - 语法糖:使多任务或多线程切换不再使用回调语法 16 | 17 | ### 2. 启动协程 18 | 19 | - runBlocking:T //用于执行协程任务 20 | - launch:Job //用于执行协程任务 21 | - async/await: Deferred //用于执行协程任务,并得到执行结果 22 | 23 | ### 3. 用协程简单请求网络 24 | 25 | 2-3句代码 ok 26 | 27 | ``` 28 | GlobalScope.launch { 29 | 30 | //发起网络请求 31 | val result = mOkHttpClient.newCall(mRequest).execute().body?.string() 32 | 33 | //这里是子线程哦 34 | Log.e("xfhy", "ThreadName = ${Thread.currentThread().name} time = ${System.currentTimeMillis()}") 35 | 36 | //阻塞的时候让出CPU 不会阻塞主线程 37 | withContext(Dispatchers.Main) { 38 | //回到主线程 39 | mContentTv.text = result 40 | } 41 | } 42 | ``` 43 | 44 | ### 4. suspend 45 | 46 | 被suspend修饰的函数只能被有suspend修饰的函数调用,因为suspend修饰的函数(或lambda)被编译之后会多一个参数类型叫Continuation.协程的异步调用本质上就是一次回调. 47 | 48 | ### 5. KTX 49 | 50 | kotlin协助Android开发的扩展库,现已加入Jetpack 51 | 52 | -------------------------------------------------------------------------------- /Android/kotlin/Kotlin相比Java 7的优势.md: -------------------------------------------------------------------------------- 1 | # Kotlin相比Java 7的优势 2 | 3 | - 它更加易表现:这是它最重要的优点之一。你可以编写少得多的代码。 4 | - 它更加安全:Kotlin是空安全的,也就是说在我们编译时期就处理了各种null的 5 | 情况,避免了执行时异常。如果一个对象可以是null,则我们需要明确地指定 6 | 它,然后在使用它之前检查它是否是null。你可以节约很多调试空指针异常的 7 | 时间,解决掉null引发的bug。 8 | - 它是函数式的:Kotlin是基于面向对象的语言。但是就如其他很多现代的语言 9 | 那样,它使用了很多函数式编程的概念,比如,使用lambda表达式来更方便地 10 | 解决问题。其中一个很棒的特性就是Collections的处理方式。 11 | - 它可以扩展函数:这意味着我们可以扩展类的更多的特性,甚至我们没有权限 12 | 去访问这个类中的代码。 13 | -它是高度互操作性的:你可以继续使用所有的你用Java写的代码和库,因为两 14 | 个语言之间的互操作性是完美的。甚至可以在一个项目中使用Kotlin和Java两 15 | 种语言混合编程。 -------------------------------------------------------------------------------- /Android/kotlin/kotlin 在Android中的应用实践.md: -------------------------------------------------------------------------------- 1 | # kotlin在Android中的应用实践 2 | 3 | 1. kotlin中使用var修饰的属性不允许不初始化,但是有的时候需要在使用的时候进行初始化,针对该情况,可以使用Delegates.notNull()代理,运行时对属性进行判断,若未初始化,则抛出java.lang.IllegalStateException异常: 4 | ```kotlin 5 | var context: Context by Delegates.notNull() 6 | private set 7 | ``` 8 | 2. 获取java的class 9 | 开启新的activity 10 | ```kotlin 11 | val intent = Intent(this, MainActivity::class.java) 12 | startActivity(intent) 13 | ``` 14 | 3. 一个lambda 表达式只有一个参数是很常见的。 如果Kotlin 可以自己计算出签名,它允许我们不声明唯一的参数,并且将隐含地为我们声明其名称为 it 15 | ```kotlin 16 | /** 17 | * 切换Fragment 18 | * @param position 下标 19 | */ 20 | private fun switchFragment(position: Int) { 21 | val transaction = supportFragmentManager.beginTransaction() 22 | hideFragments(transaction) 23 | when (position) { 24 | 0 // 首页 25 | -> mHomeFragment?.let { 26 | //it即为当前对象 这里用闭包简化了判空的过程 27 | transaction.show(it) 28 | } ?: HomeFragment.getInstance(mTitles[position]).let { //当非空时需要添加进来,进行初始化 29 | mHomeFragment = it 30 | transaction.add(R.id.fl_container, it, "home") 31 | } 32 | 1 //发现 33 | -> mDiscoveryFragment?.let { 34 | transaction.show(it) 35 | } ?: DiscoveryFragment.getInstance(mTitles[position]).let { 36 | mDiscoveryFragment = it 37 | transaction.add(R.id.fl_container, it, "discovery") } 38 | 2 //热门 39 | -> mHotFragment?.let { 40 | transaction.show(it) 41 | } ?: HotFragment.getInstance(mTitles[position]).let { 42 | mHotFragment = it 43 | transaction.add(R.id.fl_container, it, "hot") } 44 | 45 | else -> { 46 | 47 | } 48 | } 49 | } 50 | ``` 51 | 52 | 4. `?:`表示当是空的时候执行后面的语句 53 | 5. presenter懒加载(其他懒加载也是这样用的,哈哈) 54 | private val mPresenter by lazy { HomePresenter() } -------------------------------------------------------------------------------- /Android/kotlin/kotlin与Java互操作.md: -------------------------------------------------------------------------------- 1 | # Kotlin与Java互操作 2 | 3 | ## 已映射类型 4 | 5 | > Kotlin 特殊处理一部分 Java 类型。这样的类型不是“按原样”从 Java 加载,而是 映射 到相应的 Kotlin 类型。 映射只发生在编译期间,运行时表示保持不变。 Java 的原生类型映射到相应的 Kotlin 类型(请记住平台类型): 6 | 7 | ![](http://olg7c0d2n.bkt.clouddn.com/18-1-24/57383025.jpg) 8 | 9 | 一些非原生的内置类型也会作映射: 10 | ![](http://olg7c0d2n.bkt.clouddn.com/18-1-24/89378811.jpg) 11 | 12 | Java 的装箱原始类型映射到可空的 Kotlin 类型: 13 | ![](http://olg7c0d2n.bkt.clouddn.com/18-1-24/98671289.jpg) 14 | -------------------------------------------------------------------------------- /Android/kotlin/加快kotlin编译速度.md: -------------------------------------------------------------------------------- 1 | - 开启gradle daemon,即在~/.gradle/gradle.properties文件中,增加org.gradle.daemon=true 2 | - 在项目的gradle.properties中增加kotlin.incremental=true 开启kotlin的增量编译。 3 | - 尝试使用最新的kotlin版本,增加编译速度是Kotlin团队一直努力的目标 4 | - 更多的加速编译的方法,请参考[一些关于加速Gradle构建的个人经验](https://link.juejin.im/?target=http%3A%2F%2Fdroidyue.com%2Fblog%2F2017%2F04%2F16%2Fspeedup-gradle-building%2F) -------------------------------------------------------------------------------- /Android/kotlin/常用扩展.md: -------------------------------------------------------------------------------- 1 | 2 | 1. inflate一个layout 3 | ```kotlin 4 | fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View { 5 | return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot) 6 | } 7 | ``` 8 | 9 | 2. 加载图片,ImageView不能直接从网络上加载图片。我们有一些创建自定义view的库,比如:NetworkImageView,但这要求你使用继承,有时这会导致问题。现在我们知道我们可以在任何类上添加函数了,为什么不这样做呢? 10 | ```kotlin 11 | fun ImageView.loadUrl(url: String) { 12 | Picasso.with(context).load(url).into(this) 13 | } 14 | ``` 15 | -------------------------------------------------------------------------------- /Android/kotlin/扔物线教程(码上开学)/xfhy_协程理解.md: -------------------------------------------------------------------------------- 1 | 2 | ### 1. 协程是什么 3 | 4 | kotlin封装了线程的API,就是切线程 5 | 6 | ### 2. 挂起是什么 7 | 8 | 可以自动切回来的切线程 9 | 10 | ### 3. 挂起的“非阻塞式”是什么 11 | 12 | 指的是协程可以用看起来阻塞的代码,写出非阻塞式的操作 13 | 14 | 15 | -------------------------------------------------------------------------------- /Android/other/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/other/.DS_Store -------------------------------------------------------------------------------- /Android/other/Android O(8.0)新功能预览.md: -------------------------------------------------------------------------------- 1 | # Android O 8.0 新功能预览 2 | 3 | > [Android官方API](https://developer.android.com/preview/index.html)已经更新,各位Android的开发者赶快去看看啊,又有新的功能,API和限制等等出台啦.在下在这里总结了以下几点,比较重要的功能,大神勿喷.. 4 | 5 | Android官方原文https://android-developers.googleblog.com/2017/03/first-preview-of-android-o.html,我只是写下一些简单的认识,哈哈. 6 | 7 | ## 1.后台限制(Background limits) 8 | 9 | 在Android 7.0的基础上,Android O提高了用户的电池寿命和设备的交互性能一大重点。其中,这些应用程序可以在后台做,在三个主要领域:隐式广播,后台服务和位置更新。这些变化会更容易地创建具有用户的设备和电池的影响最小的应用程序。[后台执行限制](https://developer.android.com/preview/features/background.html)和[后台位置限制](https://developer.android.com/preview/features/background-location-limits.html)到这里去看看细节. 10 | 11 | ## 2.通知的渠道(Notification channels) 12 | 13 | Android O可以单独控制一个应用程序的通知,在状态栏上.而不是像之前一样把所有的应用通知都屏蔽掉. 14 | 15 | ## 3.自动填充的API(Autofill APIs) 16 | 17 | 程序员可以利用这些API很容易地实现自动填充信息和重复信息,而且Google官方还对这些数据做了保护措施,可以用于保护用户数据,如地址,用户名,甚至是密码都行.[自动填充的API在这里看](https://developer.android.com/preview/features/autofill.html) 18 | 19 | ## 4.PIP手机和新的窗口功能(PIP for handsets and new windowing features) 20 | 21 | 画中画(PIP)显示,现在手机和平板电脑都可以可用了,这样用户就可以继续观看视频,当他们在聊天或者打车。应用程序可以把自己在画中画模式从恢复或暂停状态的系统支持它-你可以指定长宽比和一套定制的互动(如播放/暂停)的. 所以当写视频播放类的软件时,应该将暂停写到onStop()中而不是onPause()中,我个人认为. 22 | 23 | ## 5.支持在XML中定义字体(Font resources in XML) 24 | 25 | ## 6.自适应图标(Adaptive icons) 26 | 27 | 现在可以创建 自适应图标,来在不同的系统环境下,显示不同的样子. 28 | 29 | ## 7.针对应用宽色域的颜色(Wide-gamut color for apps) 30 | 31 | ## 8.连接(Connectivity) 32 | 33 | Android O现在还支持高品质的蓝牙音频编解码器,如LDAC编解码器。增加了新的Wi-Fi功能,以及像 wifi网络感知,以前称为邻居感知联网(NAN)。在与相应的硬件设备,应用和附近的设备可以发现和传递通过Wi-Fi没有互联网接入点。 34 | 35 | ## 9.键盘导航(Keyboard navigation) 36 | 37 | ## 10.WebView中的增强功能(WebView enhancements) 38 | 39 | 在Android 7.0,我们引入了一个可选的多进程模式的WebView感动的网页内容处理成一个独立的进程。在Android O中,我们在默认情况下启用多进程模式和加法的API,让你的应用程序处理错误和崩溃,以提高安全性和提高应用的稳定性。也比以前更安全了. 40 | 41 | ## 11.Java 8 的API和运行时优化(Java 8 Language APIs and runtime optimizations) 42 | 43 | Android现在支持几种新的Java语言的API,包括新java.time API。另外,Android的运行时间比以往更快,最高为一些应用程序基准测试2倍的改进。 44 | -------------------------------------------------------------------------------- /Android/other/Android Studio使用.md: -------------------------------------------------------------------------------- 1 | # Androis Studio使用 2 | 3 | - alt+enter 万能键 4 | - fbc findViewById并转型 5 | - `.field` 提取成员变量 6 | - v.getId().switch 可以直接生成 7 | - boolean的变量可以.if,生成if(flag){} 8 | - new Intent().var 快速生成局部变量 -------------------------------------------------------------------------------- /Android/other/Android Studio返回上一光标处失效.md: -------------------------------------------------------------------------------- 1 | # Android Studio返回上一光标处失效 完美解决 2 | 3 | 如果把默认快捷键方式改成了Eclipse,那么原来的移动到上一处光标处的快捷键就会失效 4 | 5 | 6 | 这是default 7 | ![](http://olg7c0d2n.bkt.clouddn.com/17-8-3/24988099.jpg) 8 | 9 | 这是Eclipse模式, 10 | ![](http://olg7c0d2n.bkt.clouddn.com/17-8-3/96417709.jpg) 11 | 12 | 只需要在图中的Move Element Left的地方,右键,移除(Remove Ctrl+Alt+向左箭头)即可正常使用了 -------------------------------------------------------------------------------- /Android/other/Android 五子棋开发经验.md: -------------------------------------------------------------------------------- 1 | # Android 五子棋开发经验 # 2 | 3 | 1. 当Activity继承自AppCompatActivity,这时想要去掉标题栏的话,则需要在AndroidManifest文件中将android:theme="@style/Theme.AppCompat.Light.NoActionBar"设置成这样既可.
4 | 2. 安卓游戏音效播放(短的音效,eg:棋子下棋,枪声):
5 | 首先是短音乐(7秒以内),所以需要使用SoundPool
6 | 7 | //实例化AudioManager对象,控制声音 8 | private AudioManager audioManager =null; 9 | //最大音量 10 | float audioMaxVolumn; 11 | //当前音量 12 | float audioCurrentVolumn; 13 | float volumnRatio; 14 | //音效播放池 15 | private SoundPool playSound = new SoundPool(2,AudioManager.STREAM_MUSIC,0); 16 | //存放音效的HashMap 17 | private Map map = new HashMap(); 18 | 19 | ------------------------------------ 20 | /* 21 | 初始化游戏音效 22 | */ 23 | private void initPlaySound(){ 24 | //实例化AudioManager对象,控制声音 25 | audioManager = (AudioManager)MyApplication.getContext(). 26 | getSystemService(MyApplication.getContext().AUDIO_SERVICE); 27 | //最大音量 28 | audioMaxVolumn = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 29 | //当前音量 30 | audioCurrentVolumn = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 31 | volumnRatio = audioCurrentVolumn/audioMaxVolumn; 32 | map.put(0, playSound.load(MyApplication.getContext(),R.raw.chess_sound,1)); 33 | map.put(1, playSound.load(MyApplication.getContext(),R.raw.chess_sound,1)); 34 | } 35 | 36 | --------------------------------------------- 37 | 38 | //开始播放 39 | playSound.play( 40 | map.get(0),//声音资源 41 | volumnRatio,//左声道 42 | volumnRatio,//右声道 43 | 1,//优先级 44 | 0,//循环次数,0是不循环,-1是一直循环 45 | 1);//回放速度,0.5~2.0之间,1为正常速度 46 | 47 | 在上面的代码中,这个代码可以连续播放30次以上,而网上的那些代码我的真机测试只能播放30次左右,不知为何(谷歌,百度找了很久,没找到答案).
48 | 后来发现 49 | `private SoundPool playSound = new SoundPool(2,AudioManager.STREAM_MUSIC,0);`这个放到属性里面初始化即可,不要放到方法里面去初始化.
50 | 3.
51 |
-------------------------------------------------------------------------------- /Android/other/Android 反编译基础.md: -------------------------------------------------------------------------------- 1 | 2 | ## 1. jd-gui 3 | 4 | 用于查看jar源码,[下载地址](https://github.com/java-decompiler/jd-gui) 5 | 6 | ## 2. dex-tools-2.1-SNAPSHOT 7 | 8 | [下载地址](https://github.com/pxb1988/dex2jar) 9 | 10 | 这个工具可以将dex文件转换成jar,当然还有其他功能.可以解压缩后配置成环境变量. 11 | 12 | 解压apk文件,进入到apk解压出来的目录下面,执行下面这条命令 13 | 14 | ``` 15 | d2j-dex2jar classes.dex 16 | ``` 17 | 18 | 这条命令会将dex文件转成jar文件.有了jar文件再用上面的jd-gui进行查看源码. 19 | 20 | 不用脱壳什么的,这种方式,非常简单.这种方式已经可以拿到市面上大部分的apk源码了,但是对于梆梆加固的apk,没有效果. 21 | 22 | ## 3. 插件化 23 | 24 | 比如某安全卫士,会去下载jar包到`/data/user/0/包名`下面,这个里面访问需要root权限,然后我们找到之后,将其复制到sdcard表面,再push到电脑上.解压该jar之后,拿到dex文件,再将dex文件转成jar文件,查看源码,ok. 25 | 26 | ## 4. 反编译工具 27 | 28 | jadx,可以直接反编译一个apk,简单方便 29 | 30 | https://github.com/skylot/jadx 31 | -------------------------------------------------------------------------------- /Android/other/Android 无障碍辅助功能基础.md: -------------------------------------------------------------------------------- 1 | 2 | 1. 学习无障碍辅助功能 https://gitee.com/xfhy666/SubwayParkourCoins 3 | 2. 找到界面上的某个控件,使用工具`D:\SDK\tools\monitor.bat` 4 | -------------------------------------------------------------------------------- /Android/other/AndroidKiller 使用与配置.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://zhuanlan.zhihu.com/p/79018661 2 | 3 | AndroidKiller 使用与配置 4 | 5 | 1. 下载 AndroidKiller 工具 6 | 7 | 虽然 APK 属于压缩文件,但是 APK 包中的 AndroidManifest.xml 等文件无法通过直接解压的方式获取内容,需要通过 Apktool 工具进行反编译。在这里需要用到我们常用的反编译工具 AndroidKiller,可以到我分享的百度网盘链接 [http://pan.baidu.com/s/1dFzYtA5](https://link.zhihu.com/?target=http%3A//pan.baidu.com/s/1dFzYtA5) 密码:2gep 下载,下载解压后的目录结构如图所示。 8 | 9 | ![](https://pic4.zhimg.com/v2-41d8befbcd90bed44a0c33b76ab6182f_b.jpg)![](https://pic4.zhimg.com/v2-41d8befbcd90bed44a0c33b76ab6182f_r.jpg) 10 | 11 | 1. 配置 JDK 路径 12 | 13 | (1) 解压后第一次打开 AndroidKiller 提示没有 JDK 环境,如图所示,不用管直接点击 “OK”。 14 | 15 | ![](https://pic2.zhimg.com/v2-01d7dccf43fa707d383b648aaf4d854d_b.jpg)![](https://pic2.zhimg.com/80/v2-01d7dccf43fa707d383b648aaf4d854d_hd.jpg) 16 | 17 | (2) 打开 AndroidKiller 后,选中 “主页” 菜单栏下的 “配置” 选项, 18 | 点击 “配置” 后弹出弹窗,点击 “Java” 图标配置 JDK 所在安装路径,如图所示。 19 | 20 | ![](https://pic4.zhimg.com/v2-9c460d2e4daae90622d38d320115f0ef_b.jpg)![](https://pic4.zhimg.com/v2-9c460d2e4daae90622d38d320115f0ef_r.jpg) 21 | 22 | 2. 解决 APP 反编译失败问题 23 | 24 | (1) 由于 AndroidKiller 工具长年没有进行更新,导致很多 APP 无法反编译,需要手动更新 apktool 工具。打开 AndroidKiller 工具选中 “Android” 选项如图所示。 25 | 26 | ![](https://pic1.zhimg.com/v2-4167b4ea124bbea69922e6fa471d91f8_b.jpg)![](https://pic1.zhimg.com/v2-4167b4ea124bbea69922e6fa471d91f8_r.jpg) 27 | 28 | (2). 下载新版 apktool 工具,点击添加按钮添加下载好的 apktool 工具,如图所示 29 | 30 | ![](https://pic1.zhimg.com/v2-60a033dede27300e5b1e10302975cdb8_b.jpg)![](https://pic1.zhimg.com/v2-60a033dede27300e5b1e10302975cdb8_r.jpg) 31 | 32 | (3) 添加成功后,选择新添加的 apktool 工具,如图所示。 33 | 34 | ![](https://pic1.zhimg.com/v2-20873774fd4ba3c7305d9419e0c57ca8_b.jpg)![](https://pic1.zhimg.com/v2-20873774fd4ba3c7305d9419e0c57ca8_r.jpg) 35 | 36 | (4). 解决 APP 回编译失败问题在回编译火柴人 APP 时报错了,如图所示。 37 | 38 | ![](https://pic3.zhimg.com/v2-8cee61a7731699d905c66276e545501e_b.jpg)![](https://pic3.zhimg.com/v2-8cee61a7731699d905c66276e545501e_r.jpg) 39 | 40 | 出现这个问题的原因是 AndroidKiller 很长是时间没有更新了。 41 | 42 | 解决这个问题只需要在 apktool 工具所在路径执行该命令: 43 | 44 | java –jar apktool_2.3.4.jar empty-framework-dir 45 | 46 | 5. 更新 smali 插桩插件 47 | 48 | 打开 AndroidKiller 安装包所在位置,找到 cfgs 文件夹下的 injectcode 文件夹,将里面的插件删除。替换效果如下: 49 | 50 | ![](https://pic3.zhimg.com/v2-ef86ea232f4bdba48754c6bc127c39ce_b.jpg)![](https://pic3.zhimg.com/v2-ef86ea232f4bdba48754c6bc127c39ce_r.jpg)写下你的评论... -------------------------------------------------------------------------------- /Android/other/Android体系与系统架构.md: -------------------------------------------------------------------------------- 1 | # Android 系统架构 2 | 3 | ![](http://olg7c0d2n.bkt.clouddn.com/17-4-27/65972872-file_1493250259436_7664.png) 4 | 5 | [TOC] 6 | 7 | ## 1. Linux 8 | 9 | Android最底层最核心的部分,Linux层包含了Android系统的核心服务,包括硬件驱动,进程管理,安全系统,等等.Android 平台的基础是 Linux 内核。 10 | 例如,Android Runtime (ART) 依靠 Linux 内核来执行底层功能,例如线程和低层内存管理。使用 Linux 内核可让 Android 利用主要安全功能,并且允许设备制造商为著名的内核开发硬件驱动程序。 11 | 12 | ## 2. 硬件抽象层 (HAL) 13 | 14 | 硬件抽象层 (HAL) 提供标准界面,向更高级别的 Java API 框架显示设备硬件功能。HAL 包含多个库模块,其中每个模块都为特定类型的硬件组件实现一个界面,例如相机或蓝牙模块。当框架 API 要求访问设备硬件时,Android 系统将为该硬件组件加载库模块。 15 | 16 | ## 3. Android Runtime 和 原生 C/C++ 库 17 | 18 | **Android Runtime**:对于运行 Android 5.0(API 级别 21)或更高版本的设备,每个应用都在其自己的进程中运行,并且有其自己的 Android Runtime (ART) 实例。ART 编写为通过执行 DEX 文件在低内存设备上运行多个虚拟机,DEX 文件是一种专为 Android 设计的字节码格式,经过优化,使用的内存很少。编译工具链(例如 Jack)将 Java 源代码编译为 DEX 字节码,使其可在 Android 平台上运行。 19 | 20 | ART 的部分主要功能包括: 21 | 22 | - 预先 (AOT) 和即时 (JIT) 编译 23 | - 优化的垃圾回收 (GC) 24 | - 更好的调试支持,包括专用采样分析器、详细的诊断异常和崩溃报告,并且能够设置监视点以监控特定字段 25 | 26 | 在 Android 版本 5.0(API 级别 21)之前,Dalvik 是 Android Runtime。如果你的应用在 ART 上运行效果很好,那么它应该也可在 Dalvik 上运行,但反过来不一定。 27 | 28 | Android 还包含一套核心运行时库,可提供 Java API 框架使用的 Java 编程语言大部分功能,包括一些 Java 8 语言功能 29 | 30 | **原生 C/C++ 库:**许多核心 Android 系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的原生库。Android 平台提供 Java 框架 API 以向应用显示其中部分原生库的功能。例如,你可以通过 Android 框架的 Java OpenGL API 访问 OpenGL ES,以支持在应用中绘制和操作 2D 和 3D 图形。 31 | 32 | 如果开发的是需要 C 或 C++ 代码的应用,可以使用 Android NDK 直接从原生代码访问某些原生平台库. 33 | 34 | ## 4.Java API 框架 35 | 36 | 可通过以 Java 语言编写的 API 使用 Android OS 的整个功能集。这些 API 形成创建 Android 应用所需的构建块,它们可简化核心模块化系统组件和服务的重复使用,包括以下组件和服务: 37 | 38 | - 丰富、可扩展的视图系统,可用以构建应用的 UI,包括列表、网格、文本框、按钮甚至可嵌入的网络浏览器 39 | - 资源管理器,用于访问非代码资源,例如本地化的字符串、图形和布局文件 40 | - 通知管理器,可让所有应用在状态栏中显示自定义提醒 41 | - Activity 管理器,用于管理应用的生命周期,提供常见的导航返回栈 42 | - 内容提供程序,可让应用访问其他应用(例如“联系人”应用)中的数据或者共享其自己的数据 43 | 开发者可以完全访问 Android 系统应用使用的框架 API 44 | 45 | ## 5.系统应用 46 | 47 | Android 随附一套用于电子邮件、短信、日历、互联网浏览和联系人等的核心应用。平台随附的应用与用户可以选择安装的应用一样,没有特殊状态。因此第三方应用可成为用户的默认网络浏览器、短信 Messenger 甚至默认键盘(有一些例外,例如系统的“设置”应用)。 48 | 49 | 系统应用可用作用户的应用,以及提供开发者可从其自己的应用访问的主要功能。例如,如果你的应用要发短信,你无需自己构建该功能,可以改为调用已安装的短信应用向你指定的接收者发送消息。 50 | -------------------------------------------------------------------------------- /Android/other/Android免root查看数据库内容.md: -------------------------------------------------------------------------------- 1 | # Android免root查看数据库内容 2 | 3 | > 用Android Studio 的一个小工具 4 | 5 | ## 1.首先需要Android Studio 3.0 6 | 7 | 还没有升级AS 3.0的小伙伴赶快升级啦. 8 | AS升级方式:菜单栏Help->Check for Updates 9 | 10 | ![](http://olg7c0d2n.bkt.clouddn.com/17-11-3/77167082.jpg) 11 | 12 | ## 2.电脑插入手机 13 | 14 | 将手机打开开发者模式,打开USB调试.这里不同手机打开方式可能不同,具体的请自行百度.装上手机USB驱动,这里可以使用豌豆荚或者应用宝都行. 15 | 16 | ## 3.在AS右下角找到Device File Explorer 17 | 18 | 点击打开后,可以看到自己手机的文件信息,如下所示: 19 | ![](http://olg7c0d2n.bkt.clouddn.com/17-11-3/85444486.jpg) 20 | 21 | 如果没有显示文件信息,可能是手机驱动没装好,或者是USB调试未打开. 22 | 23 | 打开目录data/data/自己应用的包名/databases 24 | 25 | 在这个目录下存放着自己应用的数据库文件(xx.db),在需要查看的数据库文件上右键保存,保存到电脑硬盘上. 26 | ![](http://olg7c0d2n.bkt.clouddn.com/17-11-3/52990305.jpg) 27 | 28 | ## 4.下载Sqlite可视化工具 29 | 30 | 这里我使用的是SQLite Expert Personal 4,下载地址我就不贴了,百度有很多. 31 | 32 | 用可视化工具查看SqLite文件比较方便,使用方式我也不再赘述了,相信大家早就会了. 33 | 34 | ## 总结 35 | 36 | 我的测试机是vivo的,哇...根本root不了啊,然后不root查看数据库真的麻烦啊.之前用了一个三方控件,可以在浏览器上查看数据库数据,但是比较麻烦.今天终于找到简单方法了,而且非常方便.Android Studio 果然强大,点赞. 37 | -------------------------------------------------------------------------------- /Android/other/Android版本号 API对应表.md: -------------------------------------------------------------------------------- 1 | #Android版本号 API对应表 2 | 3 | - API等级7:Android 2.1 Éclair 4 | - API等级8:Android 2.2 - 2.2.3 Froyo 5 | - API等级9:Android 2.3 - 2.3.2 Gingerbread 6 | - API等级10:Android 2.3.3-2.3.7 Gingerbread 7 | - API等级11:Android 3.0 Honeycomb 专门针对平板电脑设计的 8 | - API等级12:Android 3.1 Honeycomb 9 | - API等级13:Android 3.2 Honeycomb 10 | - API等级14:Android 4.0 - 4.0.2 Ice Cream Sandwich 不再对手机和平板进行差异化区分 11 | - API等级15:Android 4.0.3 - 4.0.4 Ice Cream Sandwich 12 | - API等级16:Android 4.1 Jelly Bean 13 | - API等级17:Android 4.2 Jelly Bean 14 | - API等级18:Android 4.3 Jelly Bean 15 | - API等级19:Android 4.4 KitKat 16 | - API等级20:Android 4.4W 17 | - API等级21:Android 5.0 Lollipop 使用ART运行环境替代了Dalvik虚拟机,大大提高应用的运行速度 18 | - API等级22:Android 5.1 Lollipop 19 | - API等级23:Android 6.0 Marshmallow 运行时权限 20 | - API等级24:Android 7.0 Nougat 多窗口模式功能 -------------------------------------------------------------------------------- /Android/other/修改.aar后重新打包.md: -------------------------------------------------------------------------------- 1 | 2 | ## 替换aar中layout文件 3 | 4 | 直接在项目中新建一个与aar中文件名一致的layout文件即可 5 | 6 | ## 修改aar中的class 7 | 8 | > 比如需要修改xfhy.class 9 | 10 | 1. 解压aar,拿到classes.jar. 11 | 2. 查看xfhy.class代码,用jd-gui. 12 | 2. 用AS新建一个安卓demo,新建一个java文件,包名类名与aar中xfhy.class一致.复制第2步中的代码到这个文件中. 13 | 3. 用解压软件进入classes.jar,删除里面的xfhy.class 14 | 4. 在AS的demo中引入这个classes.jar,rebuild,拿到xfhy.class. 15 | 5. 将该xfhy.class放到classes.jar中响应位置. 16 | 6. 替换刚刚解压出来的aar文件夹中的classes.jar,打包改文件夹下所有文件(res文件、classes.jar、AndroidManifest.xml等)为xxx.aar. 打包命令为`jar cvf newAAR.aar -C tempFolder/ .` 17 | -------------------------------------------------------------------------------- /Android/other/实现圆形图片的一种骚方式.md: -------------------------------------------------------------------------------- 1 | 2 | > 其实这种官方的demo中的一个小技巧 3 | 4 | ``` 5 | 10 | ``` 11 | 12 | `avatar_1_raster`是一张普通的图片资源,`circle`是一个SVG资源(但是中心的圆形是一个缺口). 13 | 14 | `circle`的代码: 15 | 16 | ```xml 17 | 22 | 25 | 26 | ``` 27 | 28 | 预览如下,中心是一个缺口,四周是白色的(这个颜色是可以改的) 29 | ![image](408ED0CC465A4E3B87B68ED9A7B8F8C8) 30 | 31 | 实验图片如下, 32 | 33 | ![image](E26F100B495245B0B59ABD11ABDDE8BC) 34 | 35 | 36 | 最终效果: 37 | 38 | ![image](71410E9F7F3046B5AC7D6C57CA0794A0) 39 | 40 | 这种思想真是妙啊,妙啊 -------------------------------------------------------------------------------- /Android/other/屏幕适配/dpi 、 dip 、分辨率、屏幕尺寸、px、density 关系以及换算.md: -------------------------------------------------------------------------------- 1 | 适配关键: **屏幕的总 px 宽度 / density = 屏幕的总 dp 宽度** 2 | 3 | - dip : Density independent pixels ,设备无关像素。 4 | - dp :就是dip 5 | - px : 像素 6 | - dpi :dots per inch , 直接来说就是一英寸多少个像素点。常见取值 120,160,240。我一般称作像素密度,简称密度 7 | - density : 直接翻译的话貌似叫 密度。常见取值 1.5 , 1.0 。和标准dpi的比例(160px/inc).density 的意思就是 1 dp 占当前设备多少像素 8 | - 分辨率 : 横纵2个方向的像素点的数量,常见取值 480X800 ,320X480 9 | - 屏幕尺寸: 屏幕对角线的长度。电脑电视同理。 10 | - 屏幕比例的问题。因为只确定了对角线长,2边长度还不一定。所以有了4:3、16:9这种,这样就可以算出屏幕边长了。 -------------------------------------------------------------------------------- /Android/other/框架记录.md: -------------------------------------------------------------------------------- 1 | - popupmenu popup弹出菜单 https://github.com/skydoves/PowerMenu 2 | - 模糊 https://github.com/HokoFly/HokoBlur 3 | - 加密 官方加密 https://github.com/google/tink 4 | - 上滑,下拉 下拉时顶部放大 https://github.com/JmStefanAndroid/EasyBehavior 5 | - 和shape,selector说再见 https://github.com/michaelxs/Android-CommonShapeButton -------------------------------------------------------------------------------- /Android/other/自定义控件/学自定义控件看hencoder就好了: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/Android/other/自定义控件/学自定义控件看hencoder就好了 -------------------------------------------------------------------------------- /Android/other/自定义控件/自定义View 让文字居中画出来.md: -------------------------------------------------------------------------------- 1 | # 自定义View 让文字居中画出来 2 | 3 | 在onDraw()方法中调用下面的方法 4 | 5 | /** 6 | * 画文字 居中 7 | * 8 | * @param canvas 9 | */ 10 | private void canvasSche(Canvas canvas) { 11 | String text = String.valueOf(schedule); 12 | //拿到字符串的宽度 13 | mTextWidth = mTextPaint.measureText(text); 14 | //文字的x轴坐标 15 | mTextX = (getWidth() - mTextWidth) / 2; 16 | //文字的y轴坐标 17 | //描述给定文本大小的字体的各种指标的类。 18 | // 记住,Y值增加下降,所以这些值将是正的,测量距离上升的值将为负。 这个类由getFontMetrics()返回。 19 | Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics(); 20 | mTextY = getHeight() / 2 + (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2; 21 | //画字 居中显示 22 | canvas.drawText(text, mTextX, mTextY, mTextPaint); 23 | } 24 | -------------------------------------------------------------------------------- /Android/书籍笔记/Android进阶之光/HTTP协议原理.md: -------------------------------------------------------------------------------- 1 | ## HTTP协议原理 2 | 3 | ### HTTP协议主要特点 4 | 5 | - 支持C/S模式 6 | - 简单快速 7 | - 灵活 8 | - 无状态 9 | 10 | ### HTTP请求报文 11 | 12 | 由请求行,请求报头,空行,请求数据4个部分组成. 13 | 14 | 1. 请求行 15 | 16 | 请求方法: 17 | 18 | - GET请求获取Request-URI所标识的资源。 19 | - POST在Request-URI所标识的资源后附加新的数据 20 | - HEAD:请求获取由Request-URI所标识的资源的响应消息报头。 21 | - PUT:请求服务器存储一个资源,并用Request-URI作为其标识。 22 | - DELETE:请求服务器删除Request-URI所标识的资源。 23 | - TRACE:请求服务器回送收到的请求信息,主要用于测试或诊断。 24 | - CONNECT:HTTP 1.1协议中预留给能够将连接改为管道方式的代理服务器。 25 | - OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项和需求。 26 | 27 | 28 | ### HTTP响应报文 29 | 30 | HTTP 的响应报文由状态行、响应报头、空行、响应正文组成 31 | 32 | Status-Code表示服务器发回的响应状态码 33 | 34 | - 100~199:指示信息,收到请求,需要请求者继续执行操作。 35 | - 200~299:请求成功,请求已被成功接收并处理。 36 | - 300~399:重定向,要完成请求必须进行更进一步的操作。 37 | - 400~499:客户端错误,请求有语法错误或请求无法实现。 38 | - 500~599:服务器错误,服务器不能实现合法的请求。 39 | 40 | 41 | 常见的状态码如下。 42 | - • 200 OK:客户端请求成功。 43 | - • 400 Bad Request:客户端请求有语法错误,服务器无法理解。 44 | - • 401 Unauthorized:请求未经授权,这个状态码必须和WWW-Authenticate报头域一起使用。 45 | - • 403 Forbidden:服务器收到请求,但是拒绝提供服务。 46 | - • 500 Internal Server Error:服务器内部错误,无法完成请求。 47 | - • 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。 48 | 49 | 50 | ### HTTP消息报头 51 | 52 | 消息报头分为通用报头、请求报头、响应报头、实体报头等 53 | 54 | 1. 通用报头 55 | 56 | - Date:表示消息产生的日期和时间 57 | - Connection:允许发送指定连接的选项. 58 | - Cache-Control:指定缓存指令,单向,独立. 59 | 60 | 2. 请求报头 61 | 62 | - • Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。 63 | - • User-Agent:发送请求的浏览器类型、操作系统等信息。 64 | - • Accept:客户端可识别的内容类型列表,用于指定客户端接收哪些类型的信息。 65 | - • Accept-Encoding:客户端可识别的数据编码。 66 | - • Accept-Language:表示浏览器所支持的语言类型。 67 | - • Connection:允许客户端和服务器指定与请求/响应连接有关的选项。例如,这时为Keep-Alive则表示 68 | - 保持连接。 69 | - • Transfer-Encoding:告知接收端为了保证报文的可靠传输,对报文采用了什么编码方式。 70 | 71 | 3. 响应报头 72 | 73 | 用于服务器传递自身信息的响应。常见的响应报头如下所示。 74 | - • Location:用于重定向接收者到一个新的位置,常用在更换域名的时候。 75 | - • Server:包含服务器用来处理请求的系统信息,与User-Agent请求报头是相对应的。 76 | 77 | 4. 实体报头 78 | 79 | 实体报头用来定义被传送资源的信息,其既可用于请求也可用于响应。请求和响应消息都可以传送一 80 | 个实体。常见的实体报头如下所示。 81 | - • Content-Type:发送给接收者的实体正文的媒体类型。 82 | - • Content-Lenght:实体正文的长度。 83 | - • Content-Language:描述资源所用的自然语言。 84 | - • Content-Encoding:实体报头被用作媒体类型的修饰符。它的值指示了已经被应用到实体正文的附加 85 | - 内容的编码,因而要获得Content-Type报头域中所引用的媒体类型,必须采用相应的解码机制。 86 | - • Last-Modified:实体报头用于指示资源的最后修改日期和时间。 87 | - • Expires:实体报头给出响应过期的日期和时间。 -------------------------------------------------------------------------------- /Android/书籍笔记/安卓开发艺术探索/Binder.md: -------------------------------------------------------------------------------- 1 | 2 | #### Binder是什么 3 | 4 | - Binder是一个类,实现了IBinder接口 5 | - Binder是Android中的一种跨进程通信方式 6 | - Binder是ServiceManager连接各种Manager(ActivityManager,WindowManager等等)和相应ManagerService的桥梁 7 | - Binder是客户端和服务端进行通信的媒介 8 | 9 | - 客户端请求时是会挂起客户端的 10 | 11 | ![image](F93652B5D72E475A96A69DB4F5A0C14F) -------------------------------------------------------------------------------- /Android/书籍笔记/安卓开发艺术探索/Serializable和Parcelable.md: -------------------------------------------------------------------------------- 1 | 2 | 2种序列化方式 3 | 4 | ### 1. Serializable 5 | 6 | - Serializable是一个接口 7 | - serialVersionUID,在序列化和反序列化时,必须一致,不然会导致crash,序列化失败. 8 | - 可以重写系统默认的序列化和反序列化过程,重写writeObject()和readObject()方法 9 | 10 | 11 | ### 2. Parcelable 12 | 13 | 实现方式 14 | 15 | ```java 16 | public class User implements Parcelable { 17 | 18 | public int userId; 19 | public String userName; 20 | public String userSecondName; 21 | public boolean isMale; 22 | 23 | protected User(Parcel in) { 24 | userId = in.readInt(); 25 | userName = in.readString(); 26 | userSecondName = in.readString(); 27 | isMale = in.readByte() != 0; 28 | } 29 | 30 | //反序列化 交给我 31 | public static final Creator CREATOR = new Creator() { 32 | @Override 33 | public User createFromParcel(Parcel in) { 34 | return new User(in); 35 | } 36 | 37 | @Override 38 | public User[] newArray(int size) { 39 | return new User[size]; 40 | } 41 | }; 42 | 43 | @Override 44 | public int describeContents() { 45 | return 0; 46 | } 47 | 48 | //序列化 交给我 49 | @Override 50 | public void writeToParcel(Parcel dest, int flags) { 51 | dest.writeInt(userId); 52 | dest.writeString(userName); 53 | dest.writeString(userSecondName); 54 | dest.writeByte((byte) (isMale ? 1 : 0)); 55 | } 56 | } 57 | ``` 58 | 59 | - Parcel内部包装了可序列化的数据,可在Binder中自由传输 60 | - Intent,Bundle,Bitmap等都实现了Parcelable,是可以直接序列化的.List和Map其实也可以序列化,前提是他们的每个元素都是可序列化的. View是没有实现Parcelable的. 61 | 62 | ### 3. 如何进行对象序列化 63 | 64 | ```java 65 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cache.txt")); 66 | objectOutputStream.writeObject(user); 67 | objectOutputStream.close(); 68 | 69 | ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cache.txt")); 70 | User newUser = (User) objectInputStream.readObject(); 71 | System.out.println(newUser.userName); 72 | ``` 73 | 74 | 75 | ### 什么时候用哪个 76 | 77 | - Serializable是Java的,Parcelable是Android上的,Parcelable效率更高 78 | - 将Parcelable对象序列化到存储设备中或者将对象序列化后通过网络传输 可以是可以,但是过程稍显复杂,这2种情况建议使用Serializable -------------------------------------------------------------------------------- /Android/他人源码阅读笔记/KotlinMvp 小视频播放/fragment 懒加载.md: -------------------------------------------------------------------------------- 1 | 2 | - setUserVisibleHint(isVisibleToUser: Boolean)方法中的参数为true时表示当前fragment对用户可见.加载数据之后则记录状态(已加载数据) 3 | 4 | ```kotlin 5 | abstract class BaseFragment: Fragment() { 6 | 7 | /** 8 | * 视图是否加载完毕 9 | */ 10 | private var isViewPrepare = false 11 | /** 12 | * 数据是否加载过了 13 | */ 14 | private var hasLoadData = false 15 | /** 16 | * 多种状态的 View 的切换 17 | */ 18 | protected var mLayoutStatusView: MultipleStatusView? = null 19 | 20 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { 21 | return inflater?.inflate(getLayoutId(),null) 22 | } 23 | 24 | 25 | 26 | override fun setUserVisibleHint(isVisibleToUser: Boolean) { 27 | super.setUserVisibleHint(isVisibleToUser) 28 | if (isVisibleToUser) { 29 | lazyLoadDataIfPrepared() 30 | } 31 | } 32 | 33 | override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { 34 | super.onViewCreated(view, savedInstanceState) 35 | isViewPrepare = true 36 | initView() 37 | lazyLoadDataIfPrepared() 38 | //多种状态切换的view 重试点击事件 39 | mLayoutStatusView?.setOnClickListener(mRetryClickListener) 40 | } 41 | 42 | private fun lazyLoadDataIfPrepared() { 43 | if (userVisibleHint && isViewPrepare && !hasLoadData) { 44 | lazyLoad() 45 | hasLoadData = true 46 | } 47 | } 48 | 49 | open val mRetryClickListener: View.OnClickListener = View.OnClickListener { 50 | lazyLoad() 51 | } 52 | 53 | 54 | /** 55 | * 加载布局 56 | */ 57 | @LayoutRes 58 | abstract fun getLayoutId():Int 59 | 60 | /** 61 | * 初始化 ViewI 62 | */ 63 | abstract fun initView() 64 | 65 | /** 66 | * 懒加载 67 | */ 68 | abstract fun lazyLoad() 69 | 70 | override fun onDestroy() { 71 | super.onDestroy() 72 | MyApplication.getRefWatcher(activity)?.watch(activity) 73 | } 74 | } 75 | 76 | ``` 77 | -------------------------------------------------------------------------------- /Android/他人源码阅读笔记/KotlinMvp 小视频播放/kotlin fragment切换技巧.md: -------------------------------------------------------------------------------- 1 | 2 | - kotlin中when非常强大,完全可以代替if..else if,switch.when还可以用来实现判断类似java中的instanceof的作用,kotlin中是用is关键字. 3 | - 以下方式用闭包完美的简单的实现了判空操作,且展示了非空的fragment.如果fragment为空,则利用`?:`符号执行之后的初始化操作,简直完美 4 | 5 | ```kotlin 6 | /** 7 | * 切换Fragment 8 | * @param position 下标 9 | */ 10 | private fun switchFragment(position: Int) { 11 | val transaction = supportFragmentManager.beginTransaction() 12 | hideFragments(transaction) 13 | when (position) { 14 | 0 // 首页 15 | -> mHomeFragment?.let { 16 | //it即为当前对象 这里用闭包简化了判空的过程 17 | transaction.show(it) 18 | } ?: HomeFragment.getInstance(mTitles[position]).let { //当非空时需要添加进来,进行初始化 19 | mHomeFragment = it 20 | transaction.add(R.id.fl_container, it, "home") 21 | } 22 | 1 //发现 23 | -> mDiscoveryFragment?.let { 24 | transaction.show(it) 25 | } ?: DiscoveryFragment.getInstance(mTitles[position]).let { 26 | mDiscoveryFragment = it 27 | transaction.add(R.id.fl_container, it, "discovery") } 28 | 2 //热门 29 | -> mHotFragment?.let { 30 | transaction.show(it) 31 | } ?: HotFragment.getInstance(mTitles[position]).let { 32 | mHotFragment = it 33 | transaction.add(R.id.fl_container, it, "hot") } 34 | 35 | else -> { 36 | 37 | } 38 | } 39 | } 40 | ``` -------------------------------------------------------------------------------- /Android/他人源码阅读笔记/KotlinMvp 小视频播放/将扩展函数统一放到一个文件中.md: -------------------------------------------------------------------------------- 1 | 2 | - 这样做之后就非常方便了,比如在fragment中想要显示toast,直接调用showToast就行了 3 | - 扩展属性,函数是类似的 4 | 5 | ```kotlin 6 | fun Fragment.showToast(content: String): Toast { 7 | val toast = Toast.makeText(this.activity.applicationContext, content, Toast.LENGTH_SHORT) 8 | toast.show() 9 | return toast 10 | } 11 | 12 | fun Context.showToast(content: String): Toast { 13 | val toast = Toast.makeText(MyApplication.context, content, Toast.LENGTH_SHORT) 14 | toast.show() 15 | return toast 16 | } 17 | 18 | 19 | fun View.dip2px(dipValue: Float): Int { 20 | val scale = this.resources.displayMetrics.density 21 | return (dipValue * scale + 0.5f).toInt() 22 | } 23 | 24 | fun View.px2dip(pxValue: Float): Int { 25 | val scale = this.resources.displayMetrics.density 26 | return (pxValue / scale + 0.5f).toInt() 27 | } 28 | 29 | fun durationFormat(duration: Long?): String { 30 | val minute = duration!! / 60 31 | val second = duration % 60 32 | return if (minute <= 9) { 33 | if (second <= 9) { 34 | "0$minute' 0$second''" 35 | } else { 36 | "0$minute' $second''" 37 | } 38 | } else { 39 | if (second <= 9) { 40 | "$minute' 0$second''" 41 | } else { 42 | "$minute' $second''" 43 | } 44 | } 45 | } 46 | 47 | /** 48 | * 数据流量格式化 49 | */ 50 | fun Context.dataFormat(total: Long): String { 51 | var result: String 52 | var speedReal: Int = (total / (1024)).toInt() 53 | result = if (speedReal < 512) { 54 | speedReal.toString() + " KB" 55 | } else { 56 | val mSpeed = speedReal / 1024.0 57 | (Math.round(mSpeed * 100) / 100.0).toString() + " MB" 58 | } 59 | return result 60 | } 61 | ``` -------------------------------------------------------------------------------- /Android/杂乱知识点/DialogFragment全屏.md: -------------------------------------------------------------------------------- 1 | 2 | ## 方式1: 3 | 4 | ```kotlin 5 | class HomeFullInviteDialog : DialogFragment() { 6 | 7 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 8 | return inflater.inflate(R.layout.dialog_home_full_invite, container, false) 9 | } 10 | 11 | override fun onActivityCreated(savedInstanceState: Bundle?) { 12 | val window = dialog.window 13 | window?.requestFeature(Window.FEATURE_NO_TITLE) 14 | super.onActivityCreated(savedInstanceState) 15 | window?.setBackgroundDrawable(ColorDrawable(0x00000000)) 16 | window?.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT) 17 | } 18 | 19 | } 20 | ``` 21 | 22 | ## 方式2: 23 | 第一步在style中定义全屏Dialog样式 24 | ``` 25 | 30 | ``` 31 | 第二步:设置样式,以DialogFragment为例,只需要在onCreate中setStyle(STYLE_NORMAL, R.style.Dialog_FullScreen)即可。(推荐使用DialogFragment,它复用了Fragment的声明周期,被杀死后,可以恢复重建) 32 | ``` 33 | public class FragmentFullScreen extends DialogFragment { 34 | 35 | @Override 36 | public void onCreate(@Nullable Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setStyle(STYLE_NORMAL, R.style.Dialog_FullScreen); 39 | } 40 | } 41 | ``` 42 | 如果是在Dialog中,设置如下代码即可。 43 | ``` 44 | public class FullScreenDialog extends Dialog { 45 | public FullScreenDialog(Context context) { 46 | super(context); 47 | getWindow().requestFeature(Window.FEATURE_NO_TITLE); 48 | } 49 | } 50 | ``` -------------------------------------------------------------------------------- /Android/源码解析/ButterKnife/ButterKnife 原理解析.md: -------------------------------------------------------------------------------- 1 | ![](https://mmbiz.qpic.cn/mmbiz_png/v1LbPPWiaSt6VSnfwpCc1egmy69vHN2BV9nNIkvN2nUGupAfSfTBriazydoGcibAspHXhAVq77rfia22OpvnhibpVqw/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 2 | 3 | ![image](7B2DF148DA844C798DA56CC20B121255) 4 | 5 | 6 | 7 | 在上面的过程中,你可以看到,为什么用 @Bind 、 @OnClick 等注解标注的属性、方法必须是 public 或 protected? 8 | 9 | 因为ButterKnife 是通过 被代理类引用.this.editText 来注入View的。为什么要这样呢? 10 | 11 | 答案就是:性能 。如果你把 View 和方法设置成 private,那么框架必须通过反射来注入。 12 | 13 | 想深入到源码细节了解 ButterKnife 更多? 14 | 15 | how-butterknife-actually-works 16 | 17 | https://medium.com/@lgvalle/how-butterknife-actually-works-85be0afbc5ab 18 | 19 | ButterKnife源码分析 20 | 21 | https://www.jianshu.com/p/1c449c1b0fa2 22 | 23 | 拆 JakeWharton 系列之 ButterKnife 24 | 25 | https://juejin.im/post/58f388d1da2f60005d369a09 26 | 27 | ![image](25C87C5C292E4AFEA76EC268E9CB7B94) 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Android/源码解析/Retrofit/Retrofit基本使用.md: -------------------------------------------------------------------------------- 1 | 2 | > Retrofit底层是基于OkHttp实现的.与其他网络框架不同的是,它更多使用使用了运行时注解的方式提供功能. 3 | 4 | ### Retrofit的基本用法 5 | 6 | 引入 7 | ``` 8 | api 'com.squareup.retrofit2:retrofit:2.4.0' 9 | 10 | //为了增加支持返回值为 Gson 类型数据所需要添加的依赖包 11 | api 'com.squareup.retrofit2:converter-gson:2.4.0' 12 | ``` 13 | 14 | ### Retrofit的注解分类 15 | 16 | Retrofit的注解分为3大类 17 | 18 | 19 | **HTTP请求方法** 20 | 21 | - **GET** 22 | - **POST** 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 23 | - PUT 从客户端向服务器传送的数据取代指定的文档的内容。 24 | - DELETE 请求服务器删除指定的页面。 25 | - HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头 26 | - PATCH 该请求是对put请求的补充,用于更新局部资源 27 | - OPTION 允许客户端查看服务器的性能。 28 | - HTTP 通用注解, 可以替换以上所有的注解,其拥有三个属性:method,path,hasBody 29 | 30 | **标注类注解** 31 | 32 | - **FormURLEncoded** 33 | - Multipard 34 | - Streaming 35 | 36 | **参数类注解** 37 | 38 | - **Header** 作为方法的参数传入,用于添加不固定值的Header,该注解会更新已有的请求头 39 | - Headers 用于添加固定请求头,可以同时添加多个。通过该注解添加的请求头不会相互覆盖,而是共同存在 40 | - Body 多用于post请求发送非表单数据, 比如想要以post方式传递json格式数据 41 | - **Path** 用于url中的占位符,{占位符}和PATH只用在URL的path部分,url中的参数使用Query和QueryMap代替,保证接口定义的简洁 42 | - **Field** 用于post请求中表单字段, Filed和FieldMap需要FormUrlEncoded结合使用 43 | - FieldMap 和@Filed作用一致,用于不确定表单参数 44 | - Part 用于表单字段, Part和PartMap与Multipart注解结合使用, 适合文件上传的情况 45 | - PartMap 用于表单字段, 默认接受的类型是Map,可用于实现多文件上传 46 | - **Query** 用于Get中指定参数 47 | - QueryMap 和Query使用类似 48 | - ... -------------------------------------------------------------------------------- /Android/源码解析/热更新/tinker原理.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![](https://github.com/Tencent/tinker/raw/master/assets/tinker.png) 4 | 5 | tinker将old.apk和new.apk做了diff,拿到patch.dex,然后将patch.dex与本机中apk的classes.dex做了合并,生成新的classes.dex,运行时通过反射将合并后的dex文件放置在加载的dexElements数组的前面。 6 | 7 | 运行时替代的原理,其实和Qzone的方案差不多,都是去反射修改dexElements。 8 | 9 | 两者的差异是:Qzone是直接将patch.dex插到数组的前面;而tinker是将patch.dex与app中的classes.dex合并后的全量dex插在数组的前面。 10 | 11 | tinker这么做的目的还是因为Qzone方案中提到的CLASS_ISPREVERIFIED的解决方案存在问题;而tinker相当于换个思路解决了该问题。 12 | -------------------------------------------------------------------------------- /Android/第三方库的使用/Bugly.md: -------------------------------------------------------------------------------- 1 | 2 | ## 坑 3 | 4 | #### 1. Android 9.0 适配 5 | 6 | > Bugly官方文档上最高是适配的8.x,刚开始的时候我拿Android P进行测试也是无效果.后来发现log中有一句`Cleartext HTTP traffic to android.bugly.qq.com not permitted`. 拿起就是一阵Google,发现原来是Android P需要进行适配(限制了明文流量的网络请求,非加密的流量请求都会被系统禁止掉). 当我发现这个的时候,仿佛看到了一丝光明,抱着试一试的心态,搞了一下,果然可行.(测试机型为Pixel 2,Android 9.0) 7 | 8 | Android 9.0上会报以下错误,联网会失败: 9 | ``` 10 | 2018-10-10 16:39:21.312 31611-31646/com.xfhy.tinkerfirmdemo W/CrashReport: java.io.IOException: Cleartext HTTP traffic to android.bugly.qq.com not permitted 11 | at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:115) 12 | at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:458) 13 | at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127) 14 | at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:258) 15 | at com.tencent.bugly.proguard.ai.a(BUGLY:265) 16 | at com.tencent.bugly.proguard.ai.a(BUGLY:114) 17 | at com.tencent.bugly.proguard.al.run(BUGLY:355) 18 | at com.tencent.bugly.proguard.ak$1.run(BUGLY:723) 19 | at java.lang.Thread.run(Thread.java:764) 20 | 2018-10-10 16:39:21.312 31611-31646/com.xfhy.tinkerfirmdemo E/CrashReport: Failed to upload, please check your network. 21 | 2018-10-10 16:39:21.312 31611-31646/com.xfhy.tinkerfirmdemo D/CrashReport: Failed to execute post. 22 | 2018-10-10 16:39:21.312 31611-31646/com.xfhy.tinkerfirmdemo E/CrashReport: [Upload] Failed to upload(1): Failed to upload for no response! 23 | 2018-10-10 16:39:21.313 31611-31646/com.xfhy.tinkerfirmdemo E/CrashReport: [Upload] Failed to upload(1) userinfo: failed after many attempts 24 | ``` 25 | 26 | **解决办法** 27 | 28 | - 具体原因:Android P - CLEARTEXT communication not permitted by network security policy [详细介绍](http://www.douevencode.com/articles/2018-07/cleartext-communication-not-permitted/) 29 | 30 | 在资源文件新建xml目录,新建文件 31 | `network_security_config.xml` 32 | ``` 33 | 34 | 35 | 36 | android.bugly.qq.com 37 | 38 | 39 | ``` 40 | 41 | 然后在清单文件中application下加入`android:networkSecurityConfig="@xml/network_security_config"`即可 -------------------------------------------------------------------------------- /Android/第三方库的使用/Glide使用.md: -------------------------------------------------------------------------------- 1 | 2 | 1. 加载圆角 3 | ``` 4 | Glide.with(context).load(imageUrl).apply(RequestOptions.bitmapTransform(new RoundedCorners(20))).into(icon); 5 | ``` 6 | 7 | 2. 图片是gone的情况下监听不会被回调 8 | 3. -------------------------------------------------------------------------------- /Android/自定义View/3-1 触摸反馈,以及 HenCoder Plus.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://hencoder.com/ui-3-1/ 2 | 3 | 休息了几个月,HenCoder 又回来了。 4 | 5 | 这期的内容是之前说过的,自定义 View 的最后一部分:触摸反馈。触摸反馈的概念简单,但是内部逻辑比较复杂,往往把开发者难倒、让人总也学不会的也是因为逻辑太多绕不过来,所以我这次又做了一个长长的视频来讲解原理,把最本质的东西拆解开来讲,希望能让你比较舒服地吸收。视频的制作花了 5 天时间,一共 12 分钟多,全部是讲的触摸反馈的一些最核心的逻辑和原理。 6 | 7 | 细节上反而没有讲太多,因为讲这方面细节的文章,网上已经一大堆了,而且不少都写得很好。 8 | 9 | 闲话说完,放视频: 10 | 11 | 12 | 13 | 如果在页面中看不到视频,可以点 [这里](https://v.qq.com/x/page/a0684ijwxzr.html) 去看原视频。 14 | 15 | ### 总结: 16 | 17 | 自定义触摸反馈的关键: 18 | 19 | 1. 重写 `onTouchEvent()`,在里面写上你的触摸反馈算法,并返回 `true`(关键是 `ACTION_DOWN` 事件时返回 `true`)。 20 | 2. 如果是会发生触摸冲突的 `ViewGroup`,还需要重写 `onInterceptTouchEvent()`,在事件流开始时返回 `false`,并在确认接管事件流时返回一次 `true`,以实现对事件的拦截。 21 | 3. 当子 View 临时需要组织父 View 拦截事件流时,可以调用父 View 的 `requestDisallowInterceptTouchEvent()` ,通知父 View 在当前事件流中不再尝试通过 `onInterceptTouchEvent()` 来拦截。 22 | 23 | ### HenCoder Plus 24 | 25 | 另外,今天还要公布我的一个新项目:HenCoder Plus。 26 | 27 | 和 HenCoder 定位不同,HenCoder Plus 并不是一个精华技术分享,而是一个系统化的教学项目。人的技术往往是不均衡的,有些方面已经很强了,但有些方面却还比较弱,这些弱项经常会在一定高度之后限制技术人的发展。HenCoder Plus 的目的就是,针对一些最为普遍和关键性的技术短板,在短时间内进行集中教学,帮助需要的人得到快速的提升,让自己的「技术木桶」更加均衡。 28 | 29 | 为了保证事情稳步进行不出差错,HenCoder Plus 事先进行了几天时间的低调宣传,现在已经有接近 30 人参与。如果你感兴趣,可以扫下面的二维码,或者直接访问 [http://plus.hencoder.com](http://plus.hencoder.com) 来了解详情。 30 | 31 | ![](https://s1.ax1x.com/2018/06/11/Cqhq0g.png) 32 | 33 | ![](https://s1.ax1x.com/2018/06/11/Cq5C8I.png) 34 | 35 | ### 说两点 36 | 37 | 1. 最好有一定开发经验再来报名,建议是至少一年以上。因为 HenCoder Plus 是一个针对有经验的人的收费教学,我不想浪费你的钱。 38 | 2. HenCoder 还会用我习惯的方式,低频率、高质量地继续更新。 39 | 40 | * * * -------------------------------------------------------------------------------- /Android/自定义View/UI 部分 2-2 全新定义 View 的尺寸.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://hencoder.com/ui-2-2/ 2 | 3 | 这期是 HenCoder 布局部分的第二期:重写 onMeasure() 来全新定制自定义 View 的尺寸。 4 | 5 | ## 简介 6 | 7 | 这期虽然距离上期的时间比较久,但主要是我的个人原因,而不是因为这期的内容难。这期的内容还是比较简单的,主要是一些概念和原理上的东西,实操方面非常容易,所以和上期一样,主要把视频看看就差不多啦: 8 | 9 | 10 | 11 | > 在页面里看不到视频的,可以点击 [这里](https://www.bilibili.com/video/av17689063/) 去 B 站看;在海外看得卡的,可以点击 [这里](https://youtu.be/aOb4Hvqbeu4) 去 YouTube 看。 12 | 13 | ## 总结 14 | 15 | 和上期一样,这期同样是视频之后就直接是总结。 16 | 17 | 因为关键点全都在视频里讲清楚了,所以这里只总结一下视频中的关键点: 18 | 19 | ### 全新定制尺寸和修改尺寸的最重要区别 20 | 21 | 需要在计算的同时,保证计算结果满足父 View 给出的的尺寸限制 22 | 23 | ### 父 View 的尺寸限制 24 | 25 | 1. 由来:开发者的要求(布局文件中 `layout_` 打头的属性)经过父 View 处理计算后的更精确的要求; 26 | 2. 限制的分类: 27 | 28 | 1. `UNSPECIFIED`:不限制 29 | 2. `AT_MOST`:限制上限 30 | 3. `EXACTLY`:限制固定值 31 | 32 | ### 全新定义自定义 View 尺寸的方式 33 | 34 | 1. 重新 `onMeasure()`,并计算出 View 的尺寸; 35 | 2. 使用 `resolveSize()` 来让子 View 的计算结果符合父 View 的限制(当然,如果你想用自己的方式来满足父 View 的限制也行)。 36 | 37 | ## 练习项目 38 | 39 | 没有练习项目。 40 | 41 | 最近我的工作状态一直很不好,现在也还没有完全恢复,所以各位,这次就没有练习项目了。 42 | 43 | ## 下期预告 44 | 45 | 下期是布局部分的最后一期:重写 `onMeasure()` 和 `onLayout()` 来定制 `ViewGroup` 的内部布局。 46 | 47 | ## 觉得赞? 48 | 49 | 那就关注一下?↓↓↓ 50 | 51 | ![](https://ws4.sinaimg.cn/large/006tNc79ly1fl6z2sve5kj30p00bx40b.jpg) 52 | 53 | * * * -------------------------------------------------------------------------------- /Android/自定义View/UI 部分 2-3 定制 Layout 的内部布局.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://hencoder.com/ui-2-3/ 2 | 3 | 这期是 HenCoder 布局部分的最后一期:重写 `onMeasure()` 和 `onLayout()` 来定制 `Layout` 的内部布局。 4 | 5 | ## 简介 6 | 7 | 这期虽然距离上期的时间比较久,但主要是我的个人原因,而不是因为这期的内容难。这期的内容还是比较简单的,主要是一些概念和原理上的东西,实操方面非常容易,所以和上期一样,主要把视频看看就差不多啦: 8 | 9 | 10 | 11 | > 如果看不到视频,可以点 [这里](https://www.bilibili.com/video/av18330166/) 直接去 B 站看;如果你在海外,可以点 [这里](http://www.youtube.com/timedtext_video?v=fiSEB4w1lok&ref=share) 去 YouTube 上看。 12 | 13 | ## 总结 14 | 15 | 这期的文章依然是只有总结。但这次主要是因为我最近实在太多事情了…… 16 | 17 | ### 定制 Layout 内部布局的方式 18 | 19 | 1. 重写 `onMeasure()` 来计算内部布局 20 | 2. 重写 `onLayout()` 来摆放子 View 21 | 22 | ### 重写 onMeasure() 的三个步骤: 23 | 24 | 1. 调用每个子 View 的 `measure()` 来计算子 View 的尺寸 25 | 2. 计算子 View 的位置并保存子 View 的位置和尺寸 26 | 3. 计算自己的尺寸并用 `setMeasuredDimension()` 保存 27 | 28 | ### 计算子 View 尺寸的关键 29 | 30 | 计算子 View 的尺寸,关键在于 `measure()` 方法的两个参数——也就是子 View 的两个 `MeasureSpec` 的计算。 31 | 32 | #### 子 View 的 MeasureSpec 的计算方式: 33 | 34 | * 结合开发者的要求(xml 中 `layout_` 打头的属性)和自己的可用空间(自己的尺寸上限 - 已用尺寸) 35 | * 尺寸上限根据自己的 `MeasureSpec` 中的 mode 而定 36 | * EXACTLY / AT_MOST:尺寸上限为 `MeasureSpec` 中的 `size` 37 | * UNSPECIFIED:尺寸无上限 38 | 39 | ### 重写 onLayout() 的方式 40 | 41 | 在 `onLayout()` 里调用每个子 View 的 `layout()` ,让它们保存自己的位置和尺寸。 42 | 43 | ## 练习项目 44 | 45 | 这期还是没有练习项目。 46 | 47 | ## 降速生产声明 48 | 49 | 最近把 HenCoder 做得越来越溜的同时,各种工作上的事情和一些个人私事也忽然蜂拥而至。由于个人能力有限,接下来 HenCoder 将会被迫进一步降低产出速度。 50 | 51 | 呼…… 在未来的某个时间,我们下期再见啦! 52 | 53 | ## 觉得赞? 54 | 55 | 那就关注一下?↓↓↓ 56 | 57 | ![](https://ws4.sinaimg.cn/large/006tNc79ly1fl6z2sve5kj30p00bx40b.jpg) 58 | 59 | * * * -------------------------------------------------------------------------------- /Android/适配/Android P/Android 9.0限制明文流量的网络请求.md: -------------------------------------------------------------------------------- 1 | #### Android P - CLEARTEXT communication not permitted by network security policy 2 | 3 | 问题原因: Android P 限制了明文流量的网络请求,非加密的流量请求都会被系统禁止掉 4 | 5 | 解决方案: 6 | 7 | 在资源文件新建xml目录,新建文件 8 | 9 | 10 | ``` 11 | 12 | 13 | 14 | android.bugly.qq.com 15 | 16 | 17 | 18 | 清单文件配置:android:networkSecurityConfig="@xml/network_security_config" 19 | 20 | ``` 21 | 22 | 但还是建议都使用https进行传输 -------------------------------------------------------------------------------- /Android/适配/Android P/Android P 上的提醒弹窗 (Android P调用私有API etected problems with API compatibility(v.md: -------------------------------------------------------------------------------- 1 | > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 https://www.jianshu.com/p/f87fe39caf1d?tdsourcetag=s_pctim_aiomsg 2 | 3 | ##### 在 MIUI 10 升级到 Android P 后 每次进入程序都会弹一个提醒弹窗 4 | 5 | ![](https://upload-images.jianshu.io/upload_images/5757771-be0e9cd9456e256f.png) 6 | 7 | 调研了一下,是 Android P 后谷歌限制了开发者调用非官方公开 API 方法或接口,也就是说,你用反射直接调用源码就会有这样的提示弹窗出现,非 SDK 接口指的是 Android 系统内部使用、并未提供在 SDK 中的接口,开发者可能通过 Java 反射、JNI 等技术来调用这些接口。但是,这么做是很危险的:非 SDK 接口没有任何公开文档,必须查看源代码才能理解其行为逻辑。 8 | 但是源码是 JAVA 写的,万物皆可反射,所以还是可以用反射干掉这个 每次启动都会弹出的提醒窗口 9 | 10 | ``` 11 | private void closeAndroidPDialog(){ 12 | try { 13 | Class aClass = Class.forName("android.content.pm.PackageParser$Package"); 14 | Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class); 15 | declaredConstructor.setAccessible(true); 16 | } catch (Exception e) { 17 | e.printStackTrace(); 18 | } 19 | try { 20 | Class cls = Class.forName("android.app.ActivityThread"); 21 | Method declaredMethod = cls.getDeclaredMethod("currentActivityThread"); 22 | declaredMethod.setAccessible(true); 23 | Object activityThread = declaredMethod.invoke(null); 24 | Field mHiddenApiWarningShown = cls.getDeclaredField("mHiddenApiWarningShown"); 25 | mHiddenApiWarningShown.setAccessible(true); 26 | mHiddenApiWarningShown.setBoolean(activityThread, true); 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | 32 | ``` 33 | 34 | 将这个方法在 app 初始化时候调用一次,这个弹窗就不会出现了 -------------------------------------------------------------------------------- /Android/适配/Android P/getMainThreadHandler() 被hide.md: -------------------------------------------------------------------------------- 1 | ![image](D4F1D9F1EC2E4E7E8F54F0ED49BBDBF6) 2 | 3 | ContextWrapper里面的大部分方法被标记为hide 4 | 5 | 调用这些方法在Android P上会弹窗 6 | 7 | ```java 8 | /** 9 | * @hide 10 | */ 11 | @Override 12 | public Handler getMainThreadHandler() { 13 | return mBase.getMainThreadHandler(); 14 | } 15 | ``` -------------------------------------------------------------------------------- /Android/适配/android 8.0/Android 8.0开启后台Service适配.md: -------------------------------------------------------------------------------- 1 | ## 记录场景 2 | 3 | Android 8.0 有一项复杂功能;系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即 Context.startForegroundService(),以在前台启动新服务。 4 | 在系统创建服务后,应用有5秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。如果应用在此时间限制内未调用 startForeground(),则系统将停止服务并声明此应用为 ANR。 5 | 6 | 但是目前在调用:context.startForegroundService(intent)时报如下ANR,startForegroundService()文档说明在service启动后要调用startForeground()。 7 | 8 | ``` 9 | android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground() 10 | ``` 11 | 12 | ## 解决方案 13 | 14 | 使用startForegroundService启动服务后,在service的onCreate方法中调用startForeground()。 15 | 16 | 注意:在api 26 中要使用Notification.Builder(Context, String) ,并且要指明 NotificationChannel 的Id. 如果不加则会提示:Developer warning for package XXX,Failed to post notification on channel “null”. 17 | 18 | ## 最终Service代码 19 | 20 | ```kotlin 21 | class InitService : IntentService("InitService") { 22 | 23 | @TargetApi(Build.VERSION_CODES.O) 24 | override fun onCreate() { 25 | super.onCreate() 26 | //通知渠道 27 | val channel = NotificationChannel("start", "start", 28 | NotificationManager.IMPORTANCE_HIGH) 29 | 30 | //创建渠道 31 | val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 32 | manager.createNotificationChannel(channel) 33 | 34 | val notification = Notification.Builder(this, "start").build() 35 | startForeground(1, notification) 36 | } 37 | 38 | override fun onHandleIntent(intent: Intent?) { 39 | ..... 40 | } 41 | 42 | companion object { 43 | @JvmStatic 44 | fun startActionInit(context: Context) { 45 | val intent = Intent(context, InitService::class.java) 46 | //8.0以上区别对待 开启后台Service 47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 48 | context.startForegroundService(intent) 49 | } else { 50 | context.startService(intent) 51 | } 52 | } 53 | } 54 | } 55 | 56 | ``` 57 | -------------------------------------------------------------------------------- /Android/适配/各系统新特性/Andrid 7.0 新特性.md: -------------------------------------------------------------------------------- 1 | 2016.8 2 | 3 | 1.多窗口模式 4 | Android 7.0中支持多窗口多任务处理,你只要在一个应用程序中长按Overview按钮,就能进入多窗口模 5 | 式。在大屏幕设备中,同时打开两个应用程序窗口显然可以提升执行效率,例如你可以一边网上冲浪一边 6 | 发微信给自己的朋友 7 | 。 8 | 2.Data Saver 9 | Android 7.0中引入了Data Saver模式,它是一种流量保护机制。启用Data Saver模式时,系统将拦截后台 10 | 的数据使用,并在可能的情况下减少前台运行应用使用的数据量,例如限制流媒体服务的码率,下调画 11 | 质,以及减少缓存等。而通过白名单设置,用户可以让应用避免受到Data Saver模式的影响。 12 | 13 | 3.改进的Java 8语言支持 14 | Android 7.0可以支持Java 8语言平台,使得Android的Jack编译器现在能够有助于减少系统的冗余代码、 15 | 降低占用和运行时间。开发者可以直接用Lambda表达式。 16 | 17 | 4.自定义壁纸 18 | 在Android 7.0中,你可以为主屏幕设置壁纸,为锁屏设置另外一张壁纸。这个过程很简单,你只需要 19 | 选择一张图像作为壁纸,然后就会弹出一个新的提示来让你选择是将它作为主屏壁纸,还是锁屏壁纸。 20 | 21 | 5.快速回复 22 | Android 7.0还支持通知栏直接回复的功能,例如你收到一条新的Facebook Messenger或者来电,可以直 23 | 接在通知栏进行输入操作或者接听操作。值得注意的是,这个功能不仅仅限于即时通信应用,它还适用于 24 | 诸如Twitter这样的社交应用。 25 | 26 | 6.Daydream VR支持 27 | Android 7.0 内置谷歌的全新 VR 平台 Daydream。Daydream 是一个虚拟现实平台,由Daydream头盔、 28 | 手柄和智能手机构成,支持Daydream的智能手机要满足一定的硬件要求。 29 | 30 | 7.后台省电 31 | Android 7.0在后台省电方面也做了不小的改进,屏幕关闭后所有的后台进程都将会被系统限制活动, 32 | 使这些应用不会在后台中持续唤醒,从而达到省电的目的。此外,Project Svelte功能也在持续地改善,这最 33 | 大限度地减少了 Android 设备中系统和应用所占用的内存。 34 | 35 | 8.快速设置 36 | 下拉通知栏顶部可以展开快捷开关界面。在快捷开关界面右下角有一个“编辑”(EDIT)按钮,点击之 37 | 后即可自定义添加/删除快捷开关,或拖动进行排序,如图1-26所示。 38 | 39 | 40 | 9.Unicode 9支持和全新的emoji表情符号 41 | Android 7.0 支持 Unicode9,并且新增了大约 70 种emoji表情符号。这些表情符号大多数都是人形的, 42 | 并且提供不同的肤色。 43 | 44 | 45 | 10.Google Assistant 46 | Google Assistant号称融合了谷歌搜索的深度学习技术以及 Google Now 的个人信息学习技术,它能够分 47 | 辨用户的自然语言,并具备联系上下文的理解能力。这样你在向它发出指令时,就像和朋友聊天一样,无 48 | 须迎合系统而说一些生硬且古板的语句。它能够按照你的谈话内容和习惯来调整自己的推荐建议,最终能 49 | 够形成一种适合于用户本人的模式,为用户的日常生活提供帮助。 -------------------------------------------------------------------------------- /Android/适配/各系统新特性/Android 5.0 新特性.md: -------------------------------------------------------------------------------- 1 | 2014年 2 | 3 | 1.全新的 Material Design 设计风格 4 | Material Design是一种大胆的平面化创新(见图1-1)。换句话说,谷歌希望能够让Material Design给用 5 | 户带来纸张化的体验。这种新的视觉语言,在基本元素的处理上,借鉴了传统的印刷设计,以及字体版 6 | 式、网格系统、空间、比例、配色和图像使用等这些基础的平面设计规范。另外,Material Design 还推崇实 7 | 体隐喻理念,利用实体的表面与边缘的质感打造出视觉线索,让用户感受到真实性。熟悉的触感让用户可 8 | 以快速地理解并认知。在设计中可以在符合物理规律的基础上灵活地运用物质,打造出不同的使用体验。 9 | 为了吸引用户的注意力,Material Design还带来了有意义而且更合理的动态效果,以及维持整个系统的连续 10 | 性体验。需要注意的是Material Design 虽然是在 Android 5.0 时被提出来的,但是它也是在不断更新的, 11 | 12 | 2.支持多种设备 13 | Android系统的身影早已出现在多种设备中,比如:智能手机、平板电脑、笔记本电脑、智能电视、汽 14 | 车、智能手表甚至是各种家用电子产品等。 15 | 16 | 3.全新的通知中心设计 17 | 谷歌在Android 5.0中加入了全新风格的通知系统。改进后的通知系统会优先显示对用户来说比较重要 18 | 的信息,而将不太紧急的内容隐藏起来。用户只需要向下滑动就可以查看全部的通知内容 19 | 20 | 4.支持 64 位 ART虚拟机 21 | Android 5.0内部的性能上也提升了不少,它放弃了之前一直使用的Dalvik虚拟机,改用了ART虚拟机, 22 | 实现了真正的跨平台编译,在ARM、X86、MIPS 等无处不在。 23 | 24 | 5.Overview 25 | 多任务视窗现在有了一个新的名字,Overview。在界面中,每一个App都是一张独立的卡片,拥有立体 26 | 式的层叠效果,用户可以设定“最近应用程序”,通过滑动来快速切换 App,如图1-3所示。 27 | 28 | 6.设备识别解锁 29 | 现在个人识别解锁已经被普遍使用,比如当特定的智能手表出现在Android设备的附近时,就会直接绕 30 | 过锁屏界面进行操作。而Android 5.0也增加了这种针对特定设备识别解锁的模式。换句话说,当设备没有 31 | 检测到附近有可用的信任设备时,就会启动安全模式以防止未授权访问。 32 | 33 | 7.Ok Google语音指令 34 | 当手机处于待机状态时,对你的手机轻轻说声“Ok Google”,手机即刻被唤醒,只需说出简单的语言指 35 | 令,如播放音乐、查询地点、拨打电话和设定闹钟等,一切只需“说说”而已。 36 | 37 | 8.Face unlock面部解锁 38 | 在Android 5.0中,Google花费大力气优化了面部解锁功能。当用户拿起手机处理锁屏界面上的消息通知 39 | 时,面部解锁功能便自动被激活。随意浏览几条消息之后,手机已经默默地完成了面部识别。 40 | 41 | - RecyclerView 42 | - CardView 43 | - Toolbar 44 | - Notification显示等级,悬挂式Notification等 45 | - Palette 提取颜色 46 | - DrawerLayout 侧滑 -------------------------------------------------------------------------------- /Android/适配/各系统新特性/Android 6.0 新特性.md: -------------------------------------------------------------------------------- 1 | 2015.5 2 | 3 | 1.应用权限管理 4 | 在Android 6.0中,应用许可提示可以自定义了。它允许对应用的权限进行高度管理,比如应用能否使 5 | 用位置、相机、网络和通信录等,这些都开放给开发者和用户。此前的 Android 系统的应用权限管理只能 6 | 靠第三方应用来实现,在Android 6.0中应用权限管理成为系统级的功能。 7 | 8 | 2.Android Pay 9 | Android Pay是Android支付统一标准。Android 6.0系统中集成了Android Pay,其特性在于简洁、安全和 10 | 可选性。它是一个开放性平台,用户可以选择谷歌的服务或者使用银行的App来使用它。Android Pay支持 11 | Android 4.4以后的系统设备并且可以使用指纹来进行支付。 12 | 13 | 3.指纹支持 14 | 虽然很多厂商的 Android 手机实现了指纹的支持,但是这些手机都使用了非谷歌认证的技术。这一次 15 | 谷歌提供的指纹识别支持,旨在统一指纹识别的技术方案。 16 | 17 | 4.Doze电量管理 18 | Android 6.0自带Doze电量管理功能。手机静止不动一段时间后,会进入Doze电量管理模式。谷歌表 19 | 示,当屏幕处于关闭状态时,平均续航时间可提高30%。 20 | 21 | 5.App Links 22 | Android 6.0加强了软件间的关联,允许开发者将App和他们的Web域名关联。谷歌大会展示了App Links 23 | 的应用场景,比如你的手机邮箱里收到一封邮件,内文里有一个Twitter链接,点击该链接可以直接跳转到 24 | Twitter应用,而不再是网页。 25 | 26 | 6.Now on Tap 27 | 在桌面或App的任意界面,长按Home键即可激活Now on Tap,它会识别当前屏幕上的内容并创建Now 28 | 卡片。比如,你和某人聊天时提到一起去一家餐馆吃饭,这时你长按Home键,Now on Tap就会创建Now卡 29 | 片提供这家餐馆的地址和评价等相关信息。如屏幕中出现电话号码,它就会提供一个拨号的标志,你可以 30 | 直接拨打;而无须先复制,然后再粘贴到拨号界面。它还可以识别日历、地址、音乐、地标等信息。Now 31 | on Tap能够快速便捷地帮助用户,完成用户需求,这在很大程度上解放了用户的嘴和双手。这可以说是自 32 | Google Now发布以来最为重大的一次升级。 33 | 34 | 7. 运行时权限机制 35 | 在Android 6.0以前,我们安装App时会列出安装的App的访问权限,而且只有安装时会出现一次。一旦 36 | 我们同意并安装了此App,这个App就可以在用户毫不知晓的情况下访问权限内的所有东西,比如用户的通 37 | 信信息、用户的位置等,这会侵犯用户的隐私。在Android 6.0时,将不会在安装的时候授予权限;取而代 38 | 之的是,App 不得不在运行时一个一个询问用户来授予权限。对于 Android 用户来说这显然是一个好消 39 | 息;但是对于开发者来说这显然是一场噩梦,因为开发者不能像以前一样随意地调用方法了,你需要在每 40 | 个需要权限的地方检查权限,否则等待你的就是App崩溃。 -------------------------------------------------------------------------------- /Android/适配/屏幕/Android 开发中的各种单位.md: -------------------------------------------------------------------------------- 1 | 2 | - px 是作为图像构成的基本单元,单个像素的大小并不固定,跟随屏幕大小和像素数量的关系变化(屏幕越大,像素越低,单个项目越大,反之亦然).所以在使用像素作为设计单位时,在不同的设备上可能会有缩放或拉伸的情况。 3 | - resolution(分辨率) 4 | 是指屏幕的垂直和水平方向的像素数量,如果分辨率是 1920*1080 ,那就是垂直方向有 1920 个像素,水平方向有 1080 个像素。 5 | - dpi(像素密度) 6 | 是指屏幕上每英寸(1英寸 = 2.54 厘米)距离中有多少个像素点。如果屏幕为 320*240,屏幕长 2 英寸宽 1.5 英寸,Dpi = 320 / 2 = 240 / 1.5 = 160。 7 | - density(密度) 8 | 这个是指屏幕上每平方英寸(2.54 ^ 2 平方厘米)中含有的像素点数量。density 的意思就是 1 dp 占当前设备多少像素. 9 | - dip / dp (设备独立像素) 10 | 也可以叫做dp,长度单位,同一个单位在不同的设备上有不同的显示效果,具体效果根据设备的密度有关,详细的公式请看下面 。 11 | 12 | 13 | android中的dp在渲染前会将dp转为px,计算公式: 14 | - **px = density * dp;** 15 | 16 | - **density = dpi / 160;** 17 | 18 | - **px = dp * (dpi / 160);** 19 | 20 | 而dpi是根据屏幕真实的分辨率和尺寸来计算的,每个设备都可能不一样的。 -------------------------------------------------------------------------------- /Android/适配/屏幕/屏幕适配问题汇总及解决.md: -------------------------------------------------------------------------------- 1 | #### 适配的原理及怎么适配? 2 | 3 | [Android 屏幕适配从未如斯简单(8月10日最终更新版)](https://blankj.com/2018/07/30/easy-adapt-screen),由于文章写的较早,请用 1.19.2 版本及以上来完美适配。 4 | 5 | #### 如何创建 mdpi 1080 * 1920 设备的预览图? 6 | 创建新的模拟器设备,然后修改分辨率和屏幕尺寸使其达到 mdpi 即可。 7 | 8 | #### App 进入后台一段时间再进入导致适配失效? 9 | 由于进入后台可能会触发 onDestroy,导致取消了适配,从而再次进入 App 的时候可能会出现适配失效。如果是所有页面都需要适配,那就不需要在 onDestroy 里做取消适配;如果某些页面不需要适配,那就在它 setContentView 之前取消适配即可。 10 | 11 | #### webview 加载后发现 density 复原? 12 | 由于 WebView 初始化的时候会还原 density 的值导致适配失效,继承 WebView,重写如下方法: 13 | ``` 14 | @Override 15 | public void setOverScrollMode(int mode) { 16 | super.setOverScrollMode(mode); 17 | ScreenUtils.restoreAdaptScreen(); 18 | } 19 | ``` 20 | 21 | #### 如何让系统 View 尺寸正常? 22 | 后面提到的 Dialog 和 Toast 其实都可以用用这种解决方案,就是在 inflate 相关 View 之前调用 ScreenUtils#cancelAdaptScreen,show 之后调用 ScreenUtils#restoreAdaptScreen 即可,这样就可以让系统 View 显示正常尺寸。 23 | 24 | #### 显示 dialog 尺寸有问题? 25 | 如果你适配传入的不是 mdpi 下的尺寸,而是 xxhdpi,那么可能会导致 AlertDialog 跑到屏幕外边,所以在文章中我也提到了只用 mdpi 来适配,正常情况的 mdpi 是会呈现比较小的尺寸,如果你要取得和原生一致的效果,那就利用上面提到的「如何让系统 View 尺寸正常」封装下在 Dialog 显示前调用 ScreenUtils#cancelAdaptScreen,Dismiss 后根据需求看是否需要 ScreenUtils#restoreAdaptScreen;或者你也可以给 Dialog 定制统一的 styles 来解决尺寸(576dp )、字体的问题。当然,如果项目组有封装好的 Dialog,那么统一修改这个 Dialog 库的尺寸即可。 26 | 27 | #### Toast 尺寸有问题? 28 | 使用 1.19.1 及以上版本的 ToastUtils 来显示 Toast 不会有这个问题(解决之道就是上面提到的「如何让系统 View 尺寸正常」),当然你也可以自己封装不用我的 ToastUtils;或者参照 CustomToast 来自定义 Toast 布局。 29 | 30 | #### 更大尺寸的设备想要显示更多的内容? 31 | 可以使用 sw 的方案来解决尺寸更大的设备可以显示更多的内容,本方案和 sw 并没有冲突,所以如果你需要在全面屏或者大屏设备显示更多的内容可以创建新的 dimens 来解决,这样就可以做到在某一尺寸范围内的设备显示效果都一致,解决了某些人总是口口声声说「更大的屏幕就应该获取更多的信息啊」。 -------------------------------------------------------------------------------- /Android/音视频/国内外优秀音视频博客.md: -------------------------------------------------------------------------------- 1 | 国内外优秀音视频博客 2 | 3 | 收录国内外知名音视频技术相关优秀博客,主要是DaveBobo整理,感谢@DaveBobo,我补充了一些团队号及一些个人,给有志于做音视频开发的朋友一些参考。还会持续更新。 4 | 5 | 个人相关: 6 | 7 | 雷霄骅:http://blog.csdn.net/leixiaohua1020/ 8 | - 简介:雷神,永远的闪耀明星,国内音视频blog第一人 9 | 10 | 卢俊:http://ticktick.blog.51cto.com/ 11 | - 简介:直播,FFmpeg,Android音视频 12 | 13 | xiejiashu:http://blog.csdn.net/xiejiashu/ 14 | - 简介:EasyDarwin开源项目作者,音视频,FFmpeg,直播,流媒体技术 15 | 16 | 逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/ 17 | - 简介:我的博客,很不幸,也被入选了,惭愧,持续贡献吧 18 | 19 | 取次花丛懒回顾:http://blog.csdn.net/shaqoneal 20 | - 简介:殷汶杰,B站高级工程师,大量H.264编解码相关,当然不限于于此 21 | 22 | lcyw:http://blog.csdn.net/machh/ 23 | - 简介:马成海,近十年一直从事网络视频监控系统的开发,从客户端开发,音视频编解码开发,到后台服务器的开发,以及视频监控系统的架构设计 24 | 25 | 四月是你的谎言:http://windrunnerlihuan.com/ 26 | - 简介:Android 多媒体框架 27 | 28 | 陆其明:http://blog.csdn.net/happydeer/article/ 29 | - 简介:爱奇艺PC端技术总监,大咖人物,很低调 30 | 31 | 飞翔2017:http://blog.csdn.net/feixiang_john/ 32 | - 简介:流媒体,H.264,Codec, HEVC 33 | 34 | BIGBurning:http://blog.csdn.net/rootusers/ 35 | - 简介:WebRTC, FFmpeg 36 | 37 | 凯少:http://blog.csdn.net/dancing_night/article 38 | - 简介:FFmpeg,X264 39 | 40 | 李迟:http://blog.csdn.net/subfate 41 | - 简介:嵌入式开发,音视频 42 | 43 | 技术团队相关: 44 | 45 | 七牛云:http://blog.qiniu.com/ 46 | 47 | 观止云:http://blog.sina.com.cn/s/blog_166a2bafd0102y9ft.html 48 | 49 | 声网:http://blog.csdn.net/agora_cloud/ 50 | 51 | UCloud流媒体团队:http://blog.ucloud.cn/ -------------------------------------------------------------------------------- /Git/Git工作流程.md: -------------------------------------------------------------------------------- 1 | ![](http://olg7c0d2n.bkt.clouddn.com/18-2-7/56534814.jpg) -------------------------------------------------------------------------------- /Git/总结将代码托管到GitHub上.md: -------------------------------------------------------------------------------- 1 | # 代码托管到GitHub 2 | 3 | >写在前面:本文是作者通过看"Android第一行代码"Git部分后,总结归纳的,想看懂全文请务必已掌握Git版本工具的用法. 4 | 步骤如下: 5 | 6 | [TOC] 7 | 8 | ## 注册GitHub账号 9 | 10 | 1. 首先GitHub官网是`https://github.com/ ` 11 | 2. 你需要登录官网,然后注册一个GitHub账号才能使用GitHub的代码托管功能.接下来选择个人计划,收费计划有创建私人版本库的权限,如果你的软件要开源的,则可以选择免费计划就可以了. 12 | 13 | 14 | ## 创建远程仓库 15 | 16 | 1. 接下来创建自己的项目:右上角自己账户头像的左边有一个+号,点击+号即可看见有一个`New repository`按钮,这个就是拿来创建一个版本库的. 17 | 2. 点击New repository按钮后,输入项目名称(eg:`DormManager`),项目类型等. 18 | 3. 接着点击`Create repository`按钮.这个版本库就完成创建了. 19 | 4. 接下来会跳转到你的项目的版本库主页地址(eg: `https://github.com/xxxx/DormManager`). 20 | 21 | 22 | ## 将远程版本库克隆到本地 23 | 24 | 1. 接下来,需要将远程版本库克隆到本地,首先需要知道远程版本库的Git地址(其实就是上面的版本库主页地址+ .git),比如我们创建的版本库Git地址是`https://github.com/xxxx/DormManager.git . ` 25 | 2. 你现在需要到电脑本地的项目根目录下,打开`Git Bash`,接着输入`git clone https://github.com/xxxx/DormManager.git `来把远程版本库克隆到本地. 26 | 3. 接下来你的本地项目根目录下会生成一个DormManager的目录,打开进去,你会发现一些文件,比如LICENSE.现在你需要把这个目录下的所有文件复制到你的项目的根目录下面去.复制的时候别遗漏了一个.git的隐藏目录,在复制的时候千万不要漏掉. 27 | 28 | ## 将本地仓库提交到远程仓库 29 | 30 | 1. 接下来,最后一步,我们把电脑本地的项目中的所有文件提交到GitHub上面,这就很简单了,先将所有文件添加到版本控制中,如下所示: 31 | `git add .` 32 | 2. 然后在本地执行提交操作: 33 | `git commit -m "First commit"` 34 | 3. 最后将提交的内容同步到远程版本库,也就是GitHub上面: 35 | `git push origin master` 36 | 37 | **注意,最后一步的时候GitHub要求输入用户名和密码来进行身份验证,这里我们输入注册时填入的用户名和密码就可以了. 这样就已经同步完成了,现在刷新GitHub上的项目版本库主页,你会看到刚才提交的那些文件都已经存在了.** -------------------------------------------------------------------------------- /Linux/Linux GDB使用日常.md: -------------------------------------------------------------------------------- 1 | # Linux GDB使用日常 # 2 | 3 | 1. 查看断点信息:info b,单步调试输入n,查看运行的变量:p 变量名如 p i,退出调试输入q;
4 | 2. 在编译时要加上-g选项,生成的可执行文件才能用gdb进行源码级调试.
5 | gcc -g bubble.c -o bubble,继续输入gcc bubble,就可进入调试。
6 | 3. gdb提供了一个很方便的功能,在提示符下直接敲回车表示重复上一条命令
7 | 4. l --------------------> l命令相当于list,从第一行开始例出原码
8 | 5. break 16 <--------------------> 设置断点,在源程序第16行处
9 | 6. break func <--------------------> 设置断点,在函数func()入口处
10 | 7. info break <--------------------> 查看断点信息。
11 | 8. r <---------------------> 运行程序,run命令简写
12 | 9. n <---------------------> 单条语句执行,next命令简写
13 | 10. c <---------------------> 继续运行程序,continue命令简写。
14 | 11. p i <---------------------> 打印变量i的值,print命令简写。
15 | 12. bt <---------------------> 查看函数堆栈。
16 | 13. finish <---------------------> 退出函数
17 | 14. c <---------------------> 继续运行
18 | 15. q <---------------------> 退出gdb。
19 | 20 |
-------------------------------------------------------------------------------- /Linux/Linux 使用日常.md: -------------------------------------------------------------------------------- 1 | # Linux 使用日常 # 2 | 3 | 1. Ctrl+L : 在文件管理器中是编辑路径
4 | 2. Ctrl+Alt+T : 打开终端
5 | 3. 从普通用户切换到root用户,sudo -i;
6 | 4. 设置->键盘,里面可以设置截图或者其他的很多快捷键。(我设置的截图快捷键是Ctrl+Alt+A)
7 | 5. ubantu连接有线网:在终端输入sudo pppoeconf,然后输入上网账号和密码,一路确定,OK。
8 | 6. 卸载软件:sudo apt-get autoremove --purge xchm sudo ———— 获取 root 权限 9 | apt-get ——— 执行安装卸载功能的软件 10 | autoremove — 告诉 apt-get 我们所要做的操作是移除软件 11 | --purge ——— 注意这前面是两个短划线,这个参数是告诉他们要完整的干净的彻底的移除
12 |
13 | -------------------------------------------------------------------------------- /Linux/Linux 程序设计入门.md: -------------------------------------------------------------------------------- 1 | # Linux 程序设计入门 # 2 | 3 | 1. 简单的GCC语法: 4 | 5 | - gcc –c test.c,表示只编译test.c文件,成功时输出目标文件test.o
6 | - gcc –o test test.o,将test.o连接成可执行的二进制文件test
7 | - gcc –o test test.c,将test.c编译并连接成可执行的二进制文件test
8 | - -o选项表示我们要求输出的可执行文件名。
9 | - -c选项表示我们只要求编译器输出目标代码,而不必要输出可执行文件。
10 | - -g选项表示我们要求编译器在编译的时候提供我们以后对程序进行调试的信息。
11 | - $@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件.详细请查看别个大神的博客:[http://blog.csdn.net/kesaihao862/article/details/7332528](http://blog.csdn.net/kesaihao862/article/details/7332528 "引用:makefile 中 $@ $^ %< 使用")
12 | 13 | ---------- 14 | 15 | 2. makefile:在makefile中写入如下语句: 16 |

17 | main:
18 | 	gcc -o hello hello.c
19 | clean:
20 | 	rm -f hello hello.o
21 | 
22 |
23 | 在上面的代码块中,第一行的那个是默认的,比如你执行命令时输入make,则会默认执行main下面的语句. 24 | 在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。当我们输入命令 make main时,会执行编译并链接hello.c文件.当输入make clean时,会执行命令把hello 和 hello.c文件删除.是不是特别方便.
25 | 3. Linux压缩命令:
26 | gzip -cr test > 1.zip 将test文件夹压缩到1.zip中
27 | gunzip -r 1.zip > 3.txt 将1.zip解压到3.txt中
28 | tar -czvf my.tar.gz test 将test文件夹压缩到my.tar.gz中
29 | tar –zxvf my.tar.gz 将my.tar.gz解压
30 | 31 | -c :建立一个压缩文件的参数指令(create 的意思)
32 | -z :是否同时具有 gzip 的属性?亦即是否需要用 gzip 压缩?
33 | -v :压缩的过程中显示文件!这个常用,但不建议用在背景执行过程!
34 | -f :强制转换
35 | 4. 下面再插入一段makefile,继续分析 36 |

37 | 	# 变量的声明(有点像C语言里面的宏定义)
38 | objects = main.o print.o
39 | 
40 | 	# helloworld:main.o print.o 
41 | helloworld:$(objects)
42 | 	# helloworld就是我们要生成的目标
43 | 	# main.o print.o是生成此目标的先决条件
44 | 	gcc -o helloworld $(objects)
45 | 	# shell命令,最前面的一定是tab键
46 | $(objects) : print.h # 都依赖print.h
47 | 
48 | main.o:main.c print.h
49 | 	gcc -c main.c
50 | 	
51 | print.o:print.c print.h
52 | 	gcc -c print.c
53 | 
54 | clean:
55 | 	rm helloworld $(objects)
56 | 
57 | --------------------------------------------------------------------- 58 | 上面其实是3个文件,如下 59 |

60 | 1. print.h
61 |       #include
62 |       void printhello();
63 | 
64 | 2. print.c
65 |       #include"print.h"
66 |       void printhello(){
67 |         printf("Hello, world\n");
68 |       }
69 | 
70 | 3. main.c
71 |       #include "print.h"
72 |       int main(void){
73 |         printhello();
74 |         return 0;
75 |       }
76 | 
77 | ----------------------------------------------------------------- 78 | 解释一下,首先objects就像C语言里面的宏定义,在下面的任何地方都代表main.o print.o; 79 | 在helloworld那个语句之前就会执行main.o和print.o,进行编译. 80 |
81 |
-------------------------------------------------------------------------------- /Linux/Ubantu/Linux笔记/Linux GDB使用日常.md: -------------------------------------------------------------------------------- 1 | # Linux GDB使用日常 # 2 | 3 | 1. 查看断点信息:info b,单步调试输入n,查看运行的变量:p 变量名如 p i,退出调试输入q;
4 | 2. 在编译时要加上-g选项,生成的可执行文件才能用gdb进行源码级调试.
5 | gcc -g bubble.c -o bubble,继续输入gcc bubble,就可进入调试。
6 | 3. gdb提供了一个很方便的功能,在提示符下直接敲回车表示重复上一条命令
7 | 4. l --------------------> l命令相当于list,从第一行开始例出原码
8 | 5. break 16 <--------------------> 设置断点,在源程序第16行处
9 | 6. break func <--------------------> 设置断点,在函数func()入口处
10 | 7. info break <--------------------> 查看断点信息。
11 | 8. r <---------------------> 运行程序,run命令简写
12 | 9. n <---------------------> 单条语句执行,next命令简写
13 | 10. c <---------------------> 继续运行程序,continue命令简写。
14 | 11. p i <---------------------> 打印变量i的值,print命令简写。
15 | 12. bt <---------------------> 查看函数堆栈。
16 | 13. finish <---------------------> 退出函数
17 | 14. c <---------------------> 继续运行
18 | 15. q <---------------------> 退出gdb。
19 | 20 |
-------------------------------------------------------------------------------- /Linux/Ubantu/Linux笔记/Linux 使用日常.md: -------------------------------------------------------------------------------- 1 | # Linux 使用日常 # 2 | 3 | 1. Ctrl+L : 在文件管理器中是编辑路径
4 | 2. Ctrl+Alt+T : 打开终端
5 | 3. 从普通用户切换到root用户,sudo -i;
6 | 4. 设置->键盘,里面可以设置截图或者其他的很多快捷键。(我设置的截图快捷键是Ctrl+Alt+A)
7 | 5. ubantu连接有线网:在终端输入sudo pppoeconf,然后输入上网账号和密码,一路确定,OK。
8 | 6. 卸载软件:sudo apt-get autoremove --purge xchm sudo ———— 获取 root 权限 9 | apt-get ——— 执行安装卸载功能的软件 10 | autoremove — 告诉 apt-get 我们所要做的操作是移除软件 11 | --purge ——— 注意这前面是两个短划线,这个参数是告诉他们要完整的干净的彻底的移除
12 |
13 | -------------------------------------------------------------------------------- /Linux/Ubantu/vim基本操作.md: -------------------------------------------------------------------------------- 1 | # vim 基本操作 2 | 3 | > 让vim永久的显示行号:在home下新建.vimrc文件,添加set number即可。 4 | 5 | 6 | ## 进入插入模式 7 | 8 | - i:插入光标前一个字符 9 | - I:插入行首 10 | - a:插入光标后一个字符 11 | - A:插入行末 12 | - o:向下新开一行,插入行首 13 | - O:向上新开一行,插入行首 14 | 15 | ## 进入命令模式 16 | 17 | - ESC:从插入模式或末行模式进入命令模式 18 | - 移动光标 19 | - h:左移 20 | - l:右移 21 | - j:下移 22 | - k:上移 23 | 24 | - M:光标移动到中间行 25 | - L:光标移动到屏幕最后一行行首 26 | - G:移动到指定行,eg:20G 表示移动到20行 27 | 28 | - w:光标向后移动,一次移动一个单词 29 | - b:光标向前移动,一次移动一个单词 30 | 31 | - `{`:光标按段移动,上移 32 | - `}`:光标按段移动,下移 33 | 34 | - `Ctrl+d`:向下翻半屏 35 | - `Ctrl+u`:向上翻半屏 36 | 37 | - `Ctrl+f`:向下翻一屏 38 | - `Ctrl+b`:向上翻一屏 39 | 40 | - `gg`:光标移动到文件开头 41 | - G:光标移动到文件末尾 42 | 43 | ## 删除(剪切)命令 44 | 45 | - x:删除光标后一个字符,相当于del 46 | - X:删除光标前一个字符,相当于Backspace 47 | 48 | - `dd`:删除光标所在行,n dd 删除指定的行数, D:删除光标后本行的所有内容,包含光标所在字符 49 | - `d0`:删除光标前本行所有内容,不包含光标所在字符 50 | 51 | - `dw`:删除光标开始位置的单词 52 | 53 | ## 撤销命令 54 | 55 | - u:一步一步撤销 56 | - `Ctrl-r`:反撤销 57 | 58 | ## 重复命令 59 | 60 | - `.`:重复上一次操作的命令 61 | 62 | ## 文本行移动 63 | 64 | - `>>` : 文本行右移 65 | - `<<` : 文本行左移 66 | 67 | ## 复制粘贴 68 | 69 | - yy: 复制当前行, n yy: 复制n行 70 | - p : 在光标所在位置向下新开辟一行,粘贴 71 | 72 | ## 可视模式 73 | 74 | - v:按字符移动地选中文本 75 | - V:按行移动,选中文本可视模式可以配合d,y,>>,<<实现对文本块的删除,复制和左右移动 76 | 77 | ## 替换操作: 78 | 79 | - r:替换当前字符 80 | - R:替换当前行光标后的字符 81 | 82 | ## 查找命令 83 | 84 | - `/`:str 查找 85 | - n:下一个 86 | - N:上一个 87 | 88 | ## 替换命令 89 | 90 | -把abc全部替换成123 91 | - 末行模式下,将当前文件中的所有abc替换成123 :`%s/abc/123/g` 92 | - 末行模式下,将第一行至第10行之间的abc替换成123 :`1,10s/abc/123/g` 93 | 94 | ## vim里面执行shell下命令 95 | 96 | - 末行模式里输入`!`,后面跟命令 97 | -------------------------------------------------------------------------------- /Linux/Ubantu/安装Linux.md: -------------------------------------------------------------------------------- 1 | # Linux 安装记录 2 | 3 | 1.断网安装ubantu,其实这样更快。安装完了之后再去配置阿里的源,更新很快的 4 | 5 | 详细的请参考:https://github.com/gaoneng102/ubuntu-for-Android 6 | 7 | 2.配置shutter : http://blog.csdn.net/hanshileiai/article/details/46843713 8 | 9 | 3.显卡驱动是否安装上:http://blog.sina.com.cn/s/blog_4cbcf67301019cuf.html 10 | 11 | 4.linux翻墙:https://github.com/bannedbook/fanqiang 12 | 13 | 5.C/C++ 编译器:http://wiki.ubuntu.org.cn/C_Cpp_IDE 14 | -------------------------------------------------------------------------------- /Linux/Ubantu/简单使用ubantu.md: -------------------------------------------------------------------------------- 1 | 2 | - 安装软件 :sudo apt-get install xxxx 3 | - 卸载软件:sudo apt-get remove xxxx 4 | - 更新:sudo apt-get update 5 | 6 | - 安装deb软件sudo dpkg -i google-chrome-stable_current_i386.deb 7 | 装不上的解决办法:终端输入: sudo apt-get -f install 8 | 9 | - 下载东西:wget 下载地址 10 | 11 | - 按住alt+鼠标左键 拖到窗口 12 | 13 | - 安装了unity tweak tool之后,开启工作区间, 那么 Ctrl+Alt+键盘方向右键 切换工作区间 14 | 15 | - 查看指定用户正在运行的进程 ps -u xxxx 16 | 17 | - 打开任务管理器 gnome-system-monitor 18 | 19 | - 解压之后文件名乱码解决方法:unzip -O CP936 filename.zip 20 | 21 | - 在输入法为中文时输入英文标点符号 : `ctrl+.` 22 | -------------------------------------------------------------------------------- /Linux/科学上网.md: -------------------------------------------------------------------------------- 1 | # Linux下科学上网 2 | 3 | ## 一、安装Shadowsocks-Qt5 4 | 5 | ```sh 6 | sudo add-apt-repository ppa:hzwhuang/ss-qt5 7 | sudo apt-get update 8 | sudo apt-get install shadowsocks-qt5 9 | ``` 10 | 11 | ## 二、安装Chrome插件SwitchyOmega 12 | 13 | > 未科学上网前不能访问Chrome应用商店,[离线下载地址](https://github.com/FelisCatus/SwitchyOmega/releases) 14 | 15 | 1. 选择情景模式proxy,添加代理服务器 16 | 代理协议:SOCKS5,代理服务器:127.0.0.1,代理端口:1080 17 | 18 | 2. 选择情景模式auto switch,添加规则列表。选择列表格式:AutoProxy,规则列表网址:https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt,然后立即更新情景模式。然后应用选项。 19 | 20 | 3. 在`通用`里面,下载选项,更新间隔为每天一次。 21 | 22 | 4. 在Chrome右上角点一下SwitchyOmega,弹出菜单,选择`auto switch` 23 | 24 | ## 三、配置服务器到Shadowsocks-Qt5 25 | 26 | 图形化界面,操作简单,可扫二维码,导入gui_config.json等进行设置。 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | ![image](https://img.shields.io/badge/license-Apache2.0-blue.svg) 4 | [![image](https://img.shields.io/badge/author-xfhy-orange.svg)](https://github.com/xfhy) 5 | [![image](https://img.shields.io/badge/CSDN-潇风寒月-orange.svg)](https://blog.csdn.net/xfhy_) 6 | 7 | ## 简介 8 | 9 | - 平常的一些学习笔记,统一备份到这里.尽量是备份笔记,然后代码备份到其他地方. 10 | 11 | - 每天多花1小时学习新知识,不断地点亮更多的技能树. 12 | 13 | - [本人博客](http://blog.csdn.net/xfhy_) 14 | 15 | ## 程序员修养 16 | 17 | - 数据结构 18 | - [代码](https://github.com/xfhy/dataStructure) 19 | - [笔记]( https://github.com/xfhy/notes/tree/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84) 20 | - 算法 21 | - [代码](https://github.com/xfhy/Algorithm-basis) 22 | - [笔记](https://github.com/xfhy/notes/tree/master/%E7%AE%97%E6%B3%95) 23 | - 操作系统 24 | - 计算机网络 25 | - linux 26 | - git 27 | - markdown 28 | - vim(或者其他的一款适合自己的编辑器,熟练使用) 29 | - English(API还是需要看懂的) 30 | -------------------------------------------------------------------------------- /java/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/java/.DS_Store -------------------------------------------------------------------------------- /java/HashSet和TreeSet的区别.md: -------------------------------------------------------------------------------- 1 | # HashSet和TreeSet的区别 # 2 | 3 | 4 | 这个不能发表成博客,这是https://zhidao.baidu.com/question/85559012.html别人写的. 5 | 6 | 1. HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key
7 | 2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是多了一个排序的功能.
8 | 3. hashCode和equal()是HashMap用的, 因为无需排序所以只需要关注定位和唯一性即可.
9 | a. hashCode是用来计算hash值的,hash值是用来确定hash表索引的.
10 | b. hash表中的一个索引处存放的是一张链表, 所以还要通过equal方法循环比较链上的每一个对象 11 | 才可以真正定位到键值对应的Entry.
12 | c. put时,如果hash表中没定位到,就在链表前加一个Entry,如果定位到了,则更换Entry中的value,并返回旧value
13 | 4. 由于TreeMap需要排序,所以需要一个Comparator为键值进行大小比较.当然也是用Comparator定位的.
14 | a. Comparator可以在创建TreeMap时指定
15 | b. 如果创建时没有确定,那么就会使用key.compareTo()方法,这就要求key必须实现Comparable接口.
16 | c. TreeMap是使用Tree数据结构实现的,所以使用compare接口就可以完成定位了.
17 |
-------------------------------------------------------------------------------- /java/Java String学习笔记.md: -------------------------------------------------------------------------------- 1 | # Java String学习笔记 # 2 | 3 | 1. String => equalsIgnoreCase() 忽略大小写进行比较(offline)
4 | 2. 对象的方法
5 |      - inplace 改变对象的属性
6 |      - offline 未改变
7 | 3. String => trim() :去掉空格
8 | 4. String str = "java"; String池, intern(): 返回池中的有的字符串
9 | 5. StringBuffer对字符串频繁修改时,可以大大提高程序执行效率
10 | 6. System.out.println(xx); 当遇到未知的对象时,会自动调用xx.toString()方法.所以自己写的类,如果属性多的话,尽量要写toString()方法,方便调试
11 | 7. 2. StringBuilder:线程非安全的;StringBuffer:线程安全的;当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因 12 | 7. 枚举 enum Non{FAIL,E,P;}
13 |
-------------------------------------------------------------------------------- /java/Java 多态.md: -------------------------------------------------------------------------------- 1 | # Java 多态 # 2 | 3 | 1. Java中所有方法都是virtual方法(虚方法)
4 | 2. 随机数生成器Romdom,需要配合种子使用.其实这是伪随机(固定的序列,同一种子生成的随机数相同).nextInt(10)表示去的[0,10)之间的数.
5 | 3. 6 | instanceof(重点,重点,重点)   使用方法:对象 instanceof 类或接口 ,作用:判断是否为类或接口的对象. Java中强制类型转换,如果不是基本类型则必须加instanceof判断 7 |
8 | 4. 多态:①继承②方法重名(父与子)
9 | 5. Object:Java中所有类都直接或间接的继承自Object类.Object中有一些重要的方法,需要经常用到.如下: 10 | 11 | ---------- 12 | - +final getClass():Class   获取当前对象所属的类信息 13 | 14 | - +toString():String   返回当前对象本身的有关信息 15 | 16 | - equals(Object obj):boolean   比较两个对象是否是相等 17 | 18 | - =clone():clone   生成当前对象的一个拷贝 19 | 20 | - +hashCode():int   返回该对象的哈希代码值 21 | 22 | - =finalize():void   销毁对象时被调用的方法 23 | 24 | ---------- 25 | 6.为了调试方便,自定义类属性多的话,则尽量重写toString()方法
26 | 7. 如果子类中不重写Object类中的equals()方法,则equals()方法与 "==" 一样
27 | 8. System.gc():建议虚拟机进行垃圾回收.
28 | 9. 不建议在finalize()中写释放资源的代码,如果要释放资源,可以自己写一个方法,专门用于释放资源.
29 | 10. 自定义类要实现克隆,clone(),则需实现Cloneable接口,自定义一个方法,public修饰,名叫clone,返回克隆好的对象,Object中的clone()方法是非常快的.
30 | 11. 深拷贝:对自定义类中的内部类中写一个clone()方法(内部类里面也写一个克隆方法),当克隆该自定义类时,需要把内部类也克隆一次.不然就只会克隆该自定义类而自定义类里面的内部类不会被克隆.
31 | 12. 抽象类有利于代码复用,接口易于代码维护
32 |
-------------------------------------------------------------------------------- /java/Java 异常.md: -------------------------------------------------------------------------------- 1 | # Java 异常 # 2 | 3 | 1. try..catch...finally finally无论如何都会被执行到,除非catch块中有System.exit(),但是这条语句是不允许写的.
4 | 2. 如果catch块中有return,catch捕获后,先执行块中其他代码,再执行finally中的代码,最后执行catch块中的return语句
5 | 3. 如何知道调用的函数可能会抛出哪些异常,在函数定义后边写throws XXException.
6 | 4. 自定义异常,可以自己写一个类继承自Exception,并重写构造方法,传入异常信息,还可以在抛异常出传入出错的那个对象,方便跟踪错误.像下面这样,我抛出异常时,就附带了异常信息,而且还附带了出了问题的Person类,这样方便调试,能很快定位哪里出错. 7 | 8 | class MyException extends Exception{ 9 | public MyException(String message,Person person){ 10 | 11 | } 12 | } 13 |
14 | 5. Java中常见的异常
15 | ---------------------------------------------- 16 | 17 | - Exception 异常层次结构的父类 18 | - ArithmeticException 算术错误情形,如以零作除数 19 | - ArrayIndexOutOfBoundsException 数组下标越界 20 | - java.lang.NullPointerException 尝试访问 null 对象成员 21 | - ClassNotFoundException 不能加载所需的类 22 | - IllegalArgumentException 方法接收到非法参数 23 | - ClassCastException 对象强制类型转换出错 24 | - NumberFormatException 数字格式转换异常,如把"abc"转换成数字 25 | 26 | 27 | ---------------------------------------------- 28 | 6. Checked和Unchecked异常 29 | ------------------------------------------------------ 30 | - Java当中Checked异常是必须catch并处理的,而unchecked异常不强制要求程序员处理 31 | - 在处理checked异常的catch语句中,不要什么都不做 32 | - 不要直接catch Exception,这样会处理所有的异常包括checked和unchecked 33 |
34 | ------------------------------------------------------ 35 |
36 | -------------------------------------------------------------------------------- /java/Java 接口.md: -------------------------------------------------------------------------------- 1 | # Java 接口 # 2 | 3 | 1. 抽象类(主要是类) 接口,主要是偏向于功能,规则,规范,约束,一种能力等->方法.
4 | 2. 接口命名与类命名规则一致,接口的命名多半是形容词,多以able结尾表示能力.
5 | 3. 接口可以当做类型定义变量
6 | 4. 实现类实现接口必须实现所有接口的方法
7 | 5. 接口中的变量自动变为静态变量
8 | 6. 接口中所有方法自动都是public和abstract的方法
9 | 7. 接口的约定表现在注释和名字,接口的注释写下约定,如何实现方法,如何传参,如何返回等.
10 |
-------------------------------------------------------------------------------- /java/Java 类.md: -------------------------------------------------------------------------------- 1 | # Java 类 # 2 | 3 | 1. 类中的属性,eg:①private int a = 2; 构造方法中②a=4; 则①比②先执行,最后a==4;
4 | 2. this();调用本类中构造方法,必须作为第一条语句出现
5 | 3. 类图,画法: +:public , -:private, +print():void => 方法, +name:String => 属性
6 | 4. 调用父类的属性或方法: eg: super.health; super.print();
7 | 5. 使用final修饰引用型变量,变量的值是固定不变的,而变量所指向的对象的属性值是可变的
8 | 6. 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。
9 | 7. 抽象类不能用来创建对象;
10 | -------------------------------------------------------------------------------- /java/Java基础.md: -------------------------------------------------------------------------------- 1 | # Java基础(为学习java做准备) # 2 | 3 | 4 | 1. char :存储单个字符, eg:char a = '男'
5 | 2. 获取用户输入,Scanner input = new Scanner(System.in); input.hasNextInt(); //判断用户输入的是否是整数
6 | 3. 浮点数判断容差(浮点数是不能精确存储的) eg:abs(V-X) < 10E(-10) 前面的V表示要比较的那个数,X是与谁进行比较,当两数只差小于10的-10次方的时候,就认为这两个数相等
7 | 4. Java会给成员变量一个初始值,局部变量没有初始值
8 | 5. 多个方法不能相互嵌套定义
9 | 6. 包名必须全部小写,不能以圆点开头或结尾
10 | 7. 不能导入两个重名的类
11 | 8. 程序头注释必须有,程序版本,作者,用途,修改人,修改时间,修改内容
12 | 9. 方法之前写文档注释(作用,传入参数,返回值),方便别人使用时,知道这个方法该传什么值,该怎么使用等
13 | 10. 团队合作 GitHub SVN
14 | 11. 自己写方法时,传入的参数需要检查,并及时返回提示错误
15 |
-------------------------------------------------------------------------------- /java/Java核心知识点/1. 谈谈你对Java平台的理解.md: -------------------------------------------------------------------------------- 1 | Java 本身是一种面向对象的语言,最显著的特性有两个方面,一是所谓的“书写一次,到处运行”(Write once, run anywhere),能够非常容易地获得跨平台能力;另外就是垃圾收集(GC, Garbage Collection),Java 通过垃圾收集器(Garbage Collector)回收分配内存,大部分情况下,程序员不需要自己操心内存的分配和回收。 2 | 3 | 我们日常会接触到 JRE(Java Runtime Environment)或者 JDK(Java Development Kit)。 JRE,也就是 Java 运行环境,包含了 JVM 和 Java 类库,以及一些模块等。而 JDK 可以看作是 JRE 的一个超集,提供了更多工具,比如编译器、各种诊断工具等。 4 | 5 | 对于“Java 是解释执行”这句话,这个说法不太准确。我们开发的 Java 的源代码,首先通过 Javac 编译成为字节码(bytecode),然后,在运行时,通过 Java 虚拟机(JVM)内嵌的解释器将字节码转换成为最终的机器码。但是常见的 JVM,比如我们大多数情况使用的 Oracle JDK 提供的 Hotspot JVM,都提供了 JIT(Just-In-Time)编译器,也就是通常所说的动态编译器,JIT 能够在运行时将热点代码编译成机器码,这种情况下部分热点代码就属于编译执行,而不是解释执行了。 6 | 7 | 一次编译、到处运行”说的是Java语言跨平台的特性,Java的跨平台特性与Java虚拟机的存在密不可分,可在不同的环境中运行。比如说Windows平台和Linux平台都有相应的JDK,安装好JDK后也就有了Java语言的运行环境。其实Java语言本身与其他的编程语言没有特别大的差异,并不是说Java语言可以跨平台,而是在不同的平台都有可以让Java语言运行的环境而已,所以才有了Java一次编译,到处运行这样的效果。 8 | 严格的讲,跨平台的语言不止Java一种,但Java是较为成熟的一种。“一次编译,到处运行”这种效果跟编译器有关。编程语言的处理需要编译器和解释器。Java虚拟机和DOS类似,相当于一个供程序运行的平台。 9 | 10 | 程序从源代码到运行的三个阶段:编码——编译——运行——调试。Java在编译阶段则体现了跨平台的特点。编译过程大概是这样的:首先是将Java源代码转化成.CLASS文件字节码,这是第一次编译。.class文件就是可以到处运行的文件。然后Java字节码会被转化为目标机器代码,这是是由JVM来执行的,即Java的第二次编译。 11 | 12 | “到处运行”的关键和前提就是JVM。因为在第二次编译中JVM起着关键作用。在可以运行Java虚拟机的地方都内含着一个JVM操作系统。从而使JAVA提供了各种不同平台上的虚拟机制,因此实现了“到处运行”的效果。需要强调的一点是,java并不是编译机制,而是解释机制。Java字节码的设计充分考虑了JIT这一即时编译方式,可以将字节码直接转化成高性能的本地机器码,这同样是虚拟机的一个构成部分。 -------------------------------------------------------------------------------- /java/Java核心知识点/第14讲 谈谈你知道的设计模式?.md: -------------------------------------------------------------------------------- 1 | **第14讲 谈谈你知道的设计模式?** 2 | 3 | ## 典型回答 4 | 大致按照模式的应用目标分类,设计模式可以分为创建型模式、结构型模式和行为型模式。 5 | 6 | 创建型模式,是对对象创建过程的各种问题和解决方案的总结,包括各种工厂模式(Factory、Abstract Factory)、单例模式(Singleton)、构建器模式(Builder)、原型模式(ProtoType)。 7 | 8 | 结构型模式,是针对软件设计结构的总结,关注于类、对象继承、组合方式的实践经验。常见的结构型模式,包括桥接模式(Bridge)、适配器模式(Adapter)、装饰者模式(Decorator)、代理模式(Proxy)、组合模式(Composite)、外观模式(Facade)、享元模式(Flyweight)等。 9 | 10 | 行为型模式,是从类或对象之间交互、职责划分等角度总结的模式。比较常见的行为型模式有策略模式(Strategy)、解释器模式(Interpreter)、命令模式(Command)、观察者模式(Observer)、迭代器模式(Iterator)、模板方法模式(Template Method)、访问者模式(Visitor)。 11 | 12 | 如何让孩子爱上设计模式 13 | 14 | https://blog.csdn.net/column/details/14881.html 15 | -------------------------------------------------------------------------------- /java/Java核心知识点/第19讲 Java并发包提供了哪些并发工具类?.md: -------------------------------------------------------------------------------- 1 | **第19讲 | Java并发包提供了哪些并发工具类?** 2 | 3 | ## 典型回答 4 | 我们通常所说的并发包也就是 java.util.concurrent 及其子包,集中了 Java 并发的各种基础工具类,具体主要包括几个方面: 5 | 6 | 提供了比 synchronized 更加高级的各种同步结构,包括 CountDownLatch、CyclicBarrier、Semaphore 等,可以实现更加丰富的多线程操作,比如利用 Semaphore 作为资源控制器,限制同时进行工作的线程数量。 7 | 8 | 各种线程安全的容器,比如最常见的 ConcurrentHashMap、有序的 ConcunrrentSkipListMap,或者通过类似快照机制,实现线程安全的动态数组 CopyOnWriteArrayList 等。 9 | 10 | 各种并发队列实现,如各种 BlockedQueue 实现,比较典型的 ArrayBlockingQueue、 SynchorousQueue 或针对特定场景的 PriorityBlockingQueue 等。 11 | 12 | 强大的 Executor 框架,可以创建各种不同类型的线程池,调度任务运行等,绝大部分情况下,不再需要自己从头实现线程池和任务调度器。 13 | 14 | ## 知识扩展 15 | 首先,我们来看看并发包提供的丰富同步结构。前面几讲已经分析过各种不同的显式锁,今天我将专注于 16 | 17 | CountDownLatch,允许一个或多个线程等待某些操作完成。 18 | 19 | CyclicBarrier,一种辅助性的同步结构,允许多个线程等待到达某个屏障。 20 | 21 | Semaphore,Java 版本的信号量实现。 22 | 23 | Java 提供了经典信号量(Semaphore))的实现,它通过控制一定数量的允许(permit)的方式,来达到限制通用资源访问的目的。你可以想象一下这个场景,在车站、机场等出租车时,当很多空出租车就位时,为防止过度拥挤,调度员指挥排队等待坐车的队伍一次进来 5 个人上车,等这 5 个人坐车出发,再放进去下一批,这和 Semaphore 的工作原理有些类似。 24 | 25 | ## CountDownLatch的简单理解 26 | **CountDownLatch的概念** 27 | CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。 28 | 29 | CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成了任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。 30 | 31 | **CountDownLatch的用法** 32 | CountDownLatch典型用法1:某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为n new CountDownLatch(n) ,每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。 33 | 34 | CountDownLatch典型用法2:实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计数器初始化为1,多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。 35 | 36 | **CountDownLatch的不足** 37 | CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。 38 | 39 | 40 | 接下来,我来梳理下并发包里提供的线程安全 Map、List 和 Set。首先,请参考下面的类图。 41 | 42 | ![](https://static001.geekbang.org/resource/image/35/57/35390aa8a6e6f9c92fda086a1b95b457.png) 43 | 44 | 你可以看到,总体上种类和结构还是比较简单的,如果我们的应用侧重于 Map 放入或者获取的速度,而不在乎顺序,大多推荐使用 ConcurrentHashMap,反之则使用 ConcurrentSkipListMap;如果我们需要对大量数据进行非常频繁地修改,ConcurrentSkipListMap 也可能表现出优势。 45 | 46 | 关于两个 CopyOnWrite 容器,其实 CopyOnWriteArraySet 是通过包装了 CopyOnWriteArrayList 来实现的,所以在学习时,我们可以专注于理解一种。 47 | 48 | **首先,CopyOnWrite 到底是什么意思呢?它的原理是,任何修改操作,如 add、set、remove,都会拷贝原数组,修改后替换原来的数组,通过这种防御性的方式,实现另类的线程安全。** 49 | 50 | 所以这种数据结构,相对比较适合读多写少的操作,不然修改的开销还是非常明显的。 -------------------------------------------------------------------------------- /java/Java核心知识点/第2讲 Exception和Error有什么区别.md: -------------------------------------------------------------------------------- 1 | **请对比 Exception 和 Error,另外,运行时异常与一般异常有什么区别?** 2 | 3 | ## 典型回答 4 | 5 | Exception 和 Error 都是继承了 Throwable 类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。 6 | 7 | Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类。Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。 8 | 9 | Error 是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如 OutOfMemoryError 之类,都是 Error 的子类。 10 | 11 | Exception 又分为可检查(checked)异常和不检查(unchecked)异常,可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。前面我介绍的不可查的 Error,是 Throwable 不是 Exception。 12 | 13 | 不检查异常就是所谓的运行时异常,类似 NullPointerException、ArrayIndexOutOfBoundsException 之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。 14 | 15 | ## 考点分析 16 | 17 | 这张图非常重要 18 | 19 | ![](https://static001.geekbang.org/resource/image/ac/00/accba531a365e6ae39614ebfa3273900.png) 20 | 21 | ## 知识扩展 22 | 23 | - 第一,尽量不要捕获类似 Exception 这样的通用异常,而是应该捕获特定异常. 24 | 25 | 进一步讲,除非深思熟虑了,否则不要捕获 Throwable 或者 Error,这样很难保证我们能够正确程序处理 OutOfMemoryError。 26 | 27 | - 第二,不要生吞(swallow)异常。这是异常处理中要特别注意的事情,因为很可能会导致非常难以诊断的诡异情况。 28 | 29 | 生吞异常,往往是基于假设这段代码可能不会发生,或者感觉忽略异常是无所谓的,但是千万不要在产品代码做这种假设! 30 | 31 | 如果我们不把异常抛出来,或者也没有输出到日志(Logger)之类,程序可能在后续代码以不可控的方式结束。没人能够轻易判断究竟是哪里抛出了异常,以及是什么原因产生了异常。 32 | 33 | **我们从性能角度来审视一下 Java 的异常处理机制,这里有两个可能会相对昂贵的地方:** 34 | 35 | - try-catch 代码段会产生额外的性能开销,或者换个角度说,它往往会影响 JVM 对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的 try 包住整段的代码;与此同时,利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句(if/else、switch)要低效。 36 | 37 | - Java 每实例化一个 Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。 -------------------------------------------------------------------------------- /java/Java核心知识点/第4讲 强引用、软引用、弱引用、幻象引用有什么区别.md: -------------------------------------------------------------------------------- 1 | **第4讲 | 强引用、软引用、弱引用、幻象引用有什么区别? 具体使用场景是什么?** 2 | 3 | ## 典型回答 4 | 5 | 不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响。 6 | 7 | - 所谓强引用("Strong" Reference),就是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,当然具体回收时机还是要看垃圾收集策略。 8 | 9 | - 软引用(SoftReference),是一种相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象。JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用通常用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。 10 | 11 | - 弱引用(WeakReference)并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途径。这就可以用来构建一种没有特定约束的关系,比如,维护一种非强制性的映射关系,如果试图获取时对象还在,就使用它,否则重现实例化。它同样是很多缓存实现的选择。 12 | 13 | - 对于幻象引用,有时候也翻译成虚引用,你不能通过它访问对象。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制,比如,通常用来做所谓的 Post-Mortem 清理机制,我在专栏上一讲中介绍的 Java 平台自身 Cleaner 机制等,也有人利用幻象引用监控对象的创建和销毁。 14 | 15 | 16 | ## 知识扩展 17 | 18 | 1. 引用队列(ReferenceQueue)使用 19 | 20 | 谈到各种引用的编程,就必然要提到引用队列。我们在创建各种引用并关联到响应对象时,可以选择是否需要关联引用队列,JVM 会在特定时机将引用 enqueue 到队列里,我们可以从队列里获取引用(remove 方法在这里实际是有获取的意思)进行相关后续逻辑。尤其是幻象引用,get 方法只返回 null,如果再不指定引用队列,基本就没有意义了。看看下面的示例代码。利用引用队列,我们可以在对象处于相应状态时(对于幻象引用,就是前面说的被 finalize 了,处于幻象可达状态),执行后期处理逻辑。 21 | ```java 22 | Object counter = new Object(); 23 | ReferenceQueue refQueue = new ReferenceQueue<>(); 24 | PhantomReference p = new PhantomReference<>(counter, refQueue); 25 | counter = null; 26 | System.gc(); 27 | try { 28 | // Remove 是一个阻塞方法,可以指定 timeout,或者选择一直阻塞 29 | Reference ref = refQueue.remove(1000L); 30 | if (ref != null) { 31 | // do something 32 | } 33 | } catch (InterruptedException e) { 34 | // Handle it 35 | } 36 | ``` -------------------------------------------------------------------------------- /java/Java核心知识点/第7讲 int和Integer有什么区别?.md: -------------------------------------------------------------------------------- 1 | **第7讲 | int和Integer有什么区别?** 2 | 3 | int 和 Integer 有什么区别?谈谈 Integer 的值缓存范围。 4 | 5 | ## 典型回答 6 | 7 | int 是我们常说的整形数字,是 Java 的 8 个原始数据类型(Primitive Types,boolean、byte 、short、char、int、float、double、long)之一。**Java 语言虽然号称一切都是对象,但原始数据类型是例外。** 8 | 9 | Integer 是 int 对应的包装类,它有一个 int 类型的字段存储数据,并且提供了基本操作,比如数学运算、int 和字符串之间转换等。在 Java 5 中,引入了自动装箱和自动拆箱功能(boxing/unboxing),Java 可以根据上下文,自动进行转换,极大地简化了相关编程。 10 | 11 | 关于 Integer 的值缓存,这涉及 Java 5 中另一个改进。构建 Integer 对象的传统方式是直接调用构造器,直接 new 一个对象。但是根据实践,我们发现大部分数据操作都是集中在有限的、较小的数值范围,因而,在 Java 5 中新增了静态工厂方法 valueOf,在调用它的时候会利用一个缓存机制,带来了明显的性能改进。按照 Javadoc,**这个值默认缓存是 -128 到 127 之间。** 12 | 13 | ## 考点分析 14 | 15 | ## 知识扩展 16 | 17 | 1. 理解自动装箱、拆箱 18 | 19 | 自动装箱实际上算是一种语法糖。什么是语法糖?可以简单理解为 Java 平台为我们自动进行了一些转换,保证不同的写法在运行时等价,它们发生在编译阶段,也就是生成的字节码是一致的。 20 | 21 | 像前面提到的整数,javac 替我们自动把装箱转换为 Integer.valueOf(),把拆箱替换为 Integer.intValue(),这似乎这也顺道回答了另一个问题,既然调用的是 Integer.valueOf,自然能够得到缓存的好处啊。 22 | 23 | 如何程序化的验证上面的结论呢? 24 | 25 | 你可以写一段简单的程序包含下面两句代码,然后反编译一下。当然,这是一种从表现倒推的方法,大多数情况下,我们还是直接参考规范文档会更加可靠,毕竟软件承诺的是遵循规范,而不是保持当前行为。 26 | 27 | 这种缓存机制并不是只有 Integer 才有,同样存在于其他的一些包装类,比如: 28 | 29 | - Boolean,缓存了 true/false 对应实例,确切说,只会返回两个常量实例 Boolean.TRUE/FALSE。 30 | - Short,同样是缓存了 -128 到 127 之间的数值。 31 | - Byte,数值有限,所以全部都被缓存。 32 | - Character,缓存范围 '\u0000' 到 '\u007F'。 33 | 34 | 原则上,**建议避免无意中的装箱、拆箱行为**,尤其是在性能敏感的场合,创建 10 万个 Java 对象和 10 万个整数的开销可不是一个数量级的,不管是内存使用还是处理速度,光是对象头的空间占用就已经是数量级的差距了。 35 | 36 | 2. 源码分析 37 | 38 | 3. 原始类型线程安全 39 | 40 | 前面提到了线程安全设计,你有没有想过,原始数据类型操作是不是线程安全的呢? 41 | 42 | 这里可能存在着不同层面的问题: 43 | 44 | 原始数据类型的变量,显然要使用并发相关手段,才能保证线程安全,这些我会在专栏后面的并发主题详细介绍。如果有线程安全的计算需要,建议考虑使用类似 AtomicInteger、AtomicLong 这样的线程安全类。 45 | 46 | 特别的是,部分比较宽的数据类型,比如 float、double,甚至不能保证更新操作的原子性,可能出现程序读取到只更新了一半数据位的数值! -------------------------------------------------------------------------------- /java/Java核心知识点/第8讲 对比Vector、ArrayList、LinkedList有何区别?.md: -------------------------------------------------------------------------------- 1 | **第8讲 | 对比Vector、ArrayList、LinkedList有何区别?** 2 | 3 | ## 典型回答 4 | 5 | 这三者都是实现集合框架中的 List,也就是所谓的有序集合,因此具体功能也比较近似,比如都提供按照位置进行定位、添加或者删除的操作,都提供迭代器以遍历其内容等。但因为具体的设计区别,在行为、性能、线程安全等方面,表现又有很大不同。 6 | 7 | Vector 是 Java 早期提供的线程安全的动态数组,如果不需要线程安全,并不建议选择,毕竟同步是有额外开销的。Vector 内部是使用对象数组来保存数据,可以根据需要自动的增加容量,当数组已满时,会创建新的数组,并拷贝原有数组数据。 8 | 9 | ArrayList 是应用更加广泛的动态数组实现,它本身不是线程安全的,所以性能要好很多。与 Vector 近似,ArrayList 也是可以根据需要调整容量,不过两者的调整逻辑有所区别,Vector 在扩容时会提高 1 倍,而 ArrayList 则是增加 50%。 10 | 11 | LinkedList 顾名思义是 Java 提供的双向链表,所以它不需要像上面两种那样调整容量,它也不是线程安全的。 12 | 13 | ## 考点分析 14 | 15 | 一般来说,也可以补充一下不同容器类型适合的场景: 16 | 17 | - Vector 和 ArrayList 作为动态数组,其内部元素以数组形式顺序存储的,所以非常适合随机访问的场合。除了尾部插入和删除元素,往往性能会相对较差,比如我们在中间位置插入一个元素,需要移动后续所有元素。 18 | 19 | - 而 LinkedList 进行节点插入、删除却要高效得多,但是随机访问性能则要比动态数组慢。 20 | 21 | 考察 Java 集合框架,我觉得有很多方面需要掌握: 22 | 23 | - Java 集合框架的设计结构,至少要有一个整体印象。 24 | - Java 提供的主要容器(集合和 Map)类型,了解或掌握对应的数据结构、算法,思考具体技术选择。 25 | - 将问题扩展到性能、并发等领域。 26 | - 集合框架的演进与发展。 27 | 28 | 我这里以需要掌握典型排序算法为例,你至少需要熟知: 29 | - 内部排序,至少掌握基础算法如归并排序、交换排序(冒泡、快排)、选择排序、插入排序等。 30 | -外部排序,掌握利用内存和外部存储处理超大数据集,至少要理解过程和思路。 31 | 32 | ## 知识扩展 33 | 34 | ![](https://static001.geekbang.org/resource/image/67/c7/675536edf1563b11ab7ead0def1215c7.png) 35 | 36 | 我们可以看到 Java 的集合框架,Collection 接口是所有集合的根,然后扩展开提供了三大类集合,分别是: 37 | 38 | List,也就是我们前面介绍最多的有序集合,它提供了方便的访问、插入、删除等操作。 39 | 40 | Set,Set 是不允许重复元素的,这是和 List 最明显的区别,也就是不存在两个对象 equals 返回 true。我们在日常开发中有很多需要保证元素唯一性的场合。 41 | 42 | Queue/Deque,则是 Java 提供的标准队列结构的实现,除了集合的基本功能,它还支持类似先入先出(FIFO, First-in-First-Out)或者后入先出(LIFO,Last-In-First-Out)等特定行为。这里不包括 BlockingQueue,因为通常是并发编程场合,所以被放置在并发包里。 -------------------------------------------------------------------------------- /java/wamp初识,java jdbc连接mysql数据库.md: -------------------------------------------------------------------------------- 1 | ##WAMP初识,JAVA JDBC连接WAMP的MYSQL数据库## 2 | 3 | 4 | **介绍:** 5 | Windows下的Apache+Mysql/MariaDB+Perl/PHP/Python,一组常用来搭建动态网站或者服务器的开源软件,本身都是各自独立的程序,但是因为常被放在一起使用,拥有了越来越高的兼容度,共同组成了一个强大的Web应用程序平台。 6 |
7 |
8 | 首先本博客是我自己想用java连接数据库进行操作,然后我又不想用SQL(太大了,10个G啊..),所以想用一下wamp,里面有集成的一个小型数据库.是mysql的. 9 | 10 | **使用步骤:** 11 | 1. 百度下载一个wamp,安装到Windows上,全部点击下一步,即可安装完成. 12 | 2. 然后,打开wamp软件,打开浏览器输入localhost,如果出现下图所示 ![](http://i.imgur.com/tEM6nyO.png),则表示成功安装. 13 | 3. 点击左下角的phpmyadmin,将服务器排序规则设置为utf8_bin.现在可以建立数据库了,![](http://i.imgur.com/8QaQOOh.png),点击如图所示的New,新建一个数据库. 14 | 4. 建立好数据库后.用java连接数据库,具体的连接值是 jdbc.drivers=com.mysql.jdbc.Driver 15 | ; jdbc.url=jdbc:mysql://localhost:3306/DormMan?characterEncoding=utf-8 16 | ; jdbc.username=root 17 | ; jdbc.password= 18 | JAVA的代码如下 19 | 20 | Class.forName(drivers); //加载驱动 21 | //试图建立到给定数据库 URL 的连接 22 | conn = DriverManager.getConnection(url, username, password); -------------------------------------------------------------------------------- /java/接口和抽象类区别.md: -------------------------------------------------------------------------------- 1 | 总结几句话来说: 2 | 3 | 1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。 4 | 5 | 2、抽象类要被子类继承,接口要被类实现。 6 | 7 | 3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现 8 | 9 | 4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。 10 | 11 | 5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。 12 | 13 | 6、抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。 14 | 15 | 7、抽象类里可以没有抽象方法 16 | 17 | 8、如果一个类里有抽象方法,那么这个类只能是抽象类 18 | 19 | 9、抽象方法要被实现,所以不能是静态的,也不能是私有的。 20 | 21 | 10、接口可继承接口,并可多继承接口,但类只能单根继承。 -------------------------------------------------------------------------------- /操作系统/README.md: -------------------------------------------------------------------------------- 1 | ## 高频 2 | 3 | * cpu调度 4 | * 死锁的条件以及解决方案 5 | * 进程与线程的区别 6 | * 死锁是什么,什么情况下会发生死锁,手写模拟一个死锁 7 | -------------------------------------------------------------------------------- /操作系统/操作系统概述.md: -------------------------------------------------------------------------------- 1 | # 操作系统概述 2 | 3 | 4 | ## 计算机系统 5 | 6 | - 硬件系统 7 | 8 | 输入设备、输出设备、存储器、运算器和控制器。 9 | 10 | - 软件系统 11 | 12 | 应用软件,系统软件 13 | 14 | ## 什么是操作系统 15 | 16 | 操作系统位于硬件层之上,所有其他软件层之下的一种系统软件它是管理系统资源,合理组织计算机工作流程,改善人机界面,提供各种服务,为用户使用计算机提供良好运行环境的一种系统软件. 17 | 18 | ## 操作系统基本功能 19 | 20 | ### 1. 进程管理 21 | 22 | 进程控制、进程同步、进程通信、死锁处理、处理机调度等。 23 | 24 | ### 2.内存管理 25 | 内存分配、地址映射、内存保护与共享和内存扩充等功能 26 | 27 | ### 3.文件管理 28 | 文件存储空间的管理、目录管理以及文件读写管理和保护等 29 | 30 | ### 4.设备管理 31 | 完成用户的I/O请求,方便用户使用各种设备,并提高设备的利用率,主要包括缓冲管理、设备分配、设备处理和虚拟设备等功能 32 | 33 | ## 操作系统的基本特性 34 | 35 | ### 并发性 36 | 37 | 并发性是指宏观上在一段时间内能同时运行多个程序,而并行性则指同一时刻能运行多个指令。 38 | 并行需要硬件支持,如多流水线或者多处理器。 39 | 操作系统通过引入进程和线程,使得程序能够并发运行。 40 | 41 | ### 共享性 42 | 43 | 共享是指系统中的资源可以供多个并发进程共同使用。 44 | 有两种共享方式:互斥共享和同时共享。 45 | 互斥共享的资源称为临界资源,例如打印机等,在同一时间只允许一个进程访问,需要用同步机制来实现对临界资源的访问。 46 | 47 | ### 虚拟性 48 | 虚拟技术把一个物理实体转换为多个逻辑实体。 49 | 主要有两种虚拟技术:时分复用技术和空分复用技术。例如多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占有处理器,每次只执行一小个时间片并快速切换。 50 | 51 | ### 异步 52 | 异步指进程不是一次性执行完毕,而是走走停停,以不可知的速度向前推进。 53 | 54 | ## 操作系统的基本类型 55 | 56 | - 批处理系统 57 | - 分时系统 58 | - 实时系统 59 | 60 | 随着硬件技术的发展和应用深入的需要,新发展和形成的操作系统 61 | 62 | - 微机操作系统 63 | - 网络操作系统 64 | - 分布式操作系统 65 | - 嵌入式操作系统 66 | 67 | 68 | -------------------------------------------------------------------------------- /操作系统/死锁.md: -------------------------------------------------------------------------------- 1 | # 三、死锁 2 | 3 | ## 死锁的必要条件 4 | 5 | 1. 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。 6 | 2. 占有和等待:已经得到了某个资源的进程可以再请求新的资源。 7 | 3. 不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显式地释放。 8 | 4. 环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。 9 | 10 | ## 死锁的处理方法 11 | 12 | ### 1. 鸵鸟策略 13 | 14 | 把头埋在沙子里,假装根本没发生问题。 15 | 16 | 因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。 17 | 18 | 大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。 -------------------------------------------------------------------------------- /操作系统/计算机操作系统-概述.md: -------------------------------------------------------------------------------- 1 | # 一、概述 2 | 3 | ## 操作系统基本特征 4 | 5 | ### 1. 并发 6 | 并发性是指宏观上在一段时间内能同时运行多个程序,而并行性则指同一时刻能运行多个指令。 7 | 8 | 并行需要硬件支持,如多流水线或者多处理器。 9 | 10 | 操作系统通过引入进程和线程,使得程序能够并发运行。 11 | 12 | ### 2. 共享 13 | 共享是指系统中的资源可以供多个并发进程共同使用。 14 | 15 | 有两种共享方式:互斥共享和同时共享。 16 | 17 | 互斥共享的资源称为临界资源,例如打印机等,在同一时间只允许一个进程访问,需要用同步机制来实现对临界资源的访问。 18 | 19 | ### 3. 虚拟 20 | 虚拟技术把一个物理实体转换为多个逻辑实体。 21 | 22 | 主要有两种虚拟技术:时分复用技术和空分复用技术。例如多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占有处理器,每次只执行一小个时间片并快速切换。 23 | 24 | ### 4. 异步 25 | 异步指进程不是一次性执行完毕,而是走走停停,以不可知的速度向前推进。 26 | 27 | ## 操作系统基本功能 28 | 29 | ### 1. 进程管理 30 | 进程控制、进程同步、进程通信、死锁处理、处理机调度等。 31 | 32 | ### 2. 内存管理 33 | 内存分配、地址映射、内存保护与共享和内存扩充等功能。 34 | 35 | ### 3. 文件管理 36 | 文件存储空间的管理、目录管理及文件读写管理和保护等。 37 | 38 | ### 4. 设备管理 39 | 完成用户的 I/O 请求,方便用户使用各种设备,并提高设备的利用率,主要包括缓冲管理、设备分配、设备处理和虛拟设备等功能。 40 | -------------------------------------------------------------------------------- /数据结构与算法/README.md: -------------------------------------------------------------------------------- 1 | ## 基础 2 | 3 | 数据结构仓库: https://github.com/xfhy/dataStructure 4 | 算法仓库: https://github.com/xfhy/Algorithm-basis 5 | 6 | 数据结构与算法,是紧紧联系在一起的. 7 | -------------------------------------------------------------------------------- /数据结构与算法/常用数据结构与算法及学习技巧.md: -------------------------------------------------------------------------------- 1 | 2 | 这里面有 : 3 | 4 | - 10 个数据结构: 数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树; 5 | - 10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法。 6 | - 7 | 8 | #### 学习技巧 9 | 10 | - 边学边练 每周花1-2小时,把代码全实现一遍 11 | - 多问,多思考,多互动 12 | - 打怪升级学习法 13 | - 知识需要沉淀,不要想视图一下子掌握所有 -------------------------------------------------------------------------------- /数据结构与算法/排序/冒泡排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/数据结构与算法/排序/冒泡排序.cpp -------------------------------------------------------------------------------- /数据结构与算法/排序/合并排序(归并排序).cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/数据结构与算法/排序/合并排序(归并排序).cpp -------------------------------------------------------------------------------- /数据结构与算法/排序/常见排序算法.md: -------------------------------------------------------------------------------- 1 | # 常见排序算法 2 | 3 | # 稳定排序 4 | 5 | - 冒泡排序(Bubble Sort) — O(n²) 6 | - 插入排序(Insertion Sort)— O(n²) 7 | - 桶排序(Bucket Sort)— O(n); 需要 O(k) 额外空间 8 | - 计数排序 (Counting Sort) — O(n+k); 需要 O(n+k) 额外空间 9 | - 合并排序(Merge Sort)— O(nlogn); 需要 O(n) 额外空间 10 | - 二叉排序树排序 (Binary tree sort) — O(n log n) 期望时间; O(n²)最坏时间; 需要 O(n) 额外空间 11 | - 基数排序(Radix sort)— O(n·k); 需要 O(n) 额外空间 12 | 13 | # 不稳定排序 14 | 15 | - 选择排序(Selection Sort)— O(n²) 16 | - 希尔排序(Shell Sort)— O(nlogn) 17 | - 堆排序(Heapsort)— O(nlogn) 18 | - 快速排序(Quicksort)— O(nlogn) 期望时间, O(n²) 最坏情况; 对于大的、乱数串行一般相信是最快的已知排序. 19 | 20 | 21 | 22 | ## 快速排序 23 | 24 | ![](http://olg7c0d2n.bkt.clouddn.com/17-3-22/41915832-file_1490163848709_74ad.gif) 25 | 26 | 27 | -------------------------------------------------------------------------------- /数据结构与算法/排序/快速排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/数据结构与算法/排序/快速排序.cpp -------------------------------------------------------------------------------- /数据结构与算法/排序/插入排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/数据结构与算法/排序/插入排序.cpp -------------------------------------------------------------------------------- /数据结构与算法/排序/桶排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/数据结构与算法/排序/桶排序.cpp -------------------------------------------------------------------------------- /数据结构与算法/排序/计数排序.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfhy/notes/26f6b1b78a1b93f24284aa70414882efd3e3ee98/数据结构与算法/排序/计数排序.cpp -------------------------------------------------------------------------------- /计算机网络/IP.md: -------------------------------------------------------------------------------- 1 | # IP基础知识 2 | 3 | [TOC] 4 | 5 | # 1. IP地址分类 6 | 7 | ## 1. A类地址 8 | 9 | - A类地址范围:1.0.0.1--126.255.255.254 10 | - 10.X.X.X是私有地址 所谓的私有地址就是在互联网上不使用,而被用在局域网中的地址. 11 | - 127.X.X.X是保留地址,用作循环测试用的 12 | 13 | ## 2. B类地址 14 | 15 | - B类地址第1字节和第2字节为网络地址,其他2个字节为主机地址.它的第1个字节的前两位固定为10. 16 | - B类地址范围:128.0.0.1--191.255.255.254 17 | 18 | ## 3. C类地址 19 | 20 | - C类地址第1字节,第2字节和第3字节为网络地址,第4个字节为主机地址.另外,第1个字节的前三位固定为110. 21 | - C类地址范围:192.0.0.1--223.255.255.254 22 | 23 | ## 4. D类地址 24 | 25 | - D类地址部分网络地址和主机地址,它的第1个字节的前4位固定为1110. 26 | - D类地址范围: 224.0.0.1--239.255.255.254 27 | 28 | ## 5. E类地址 29 | 30 | - E类地址部分网络地址和主机地址,它的第1个字节的前四位固定为1110. 31 | - D类地址范围: 240.0.0.1--255.255.255.254 -------------------------------------------------------------------------------- /计算机网络/README.md: -------------------------------------------------------------------------------- 1 | ## 高频 2 | 3 | * 常见的http状态码的含义 4 | * 304与200的区别 5 | * HTTP, UDP, TCP 6 | * 三次握手, 四次挥手 7 | * https, http2 8 | * GET与POST区别 9 | * tcp原理 10 | * 304缓存的原理 11 | * 域名收敛是什么 12 | * restful method的解释 13 | * socket套接字是在协议中的哪一层? 14 | * accept是什么,怎么用 15 | * 301, 302, 303, 307区别 16 | * tcp与udp特点与区别 17 | * tcp的可靠传输以及流量控制是如何实现的 18 | * ip协议需要知道端口吗 19 | * https的加密在哪一层实现 20 | * CDN路由回溯定向 21 | * 正常情况下,如果浏览器已经登录了百度账号,再另外打开一个tab页是会自动保持登录状态的,问怎样杜绝这个事情,使得每一次打开都是重新登录,给出实现方案。 22 | 23 | ## get和post的区别 24 | 25 | * HTTP规范指出,get从服务器上获取资源,post是向服务器上传资源 26 | * get传输的数据量小,post传输的数据量相对大一些。 27 | * get数据在url中可见,post数据不会显示在url中。 28 | * post安全性更高,因为参数不会被保存在浏览器历史中以及服务器日历中。 29 | * get请求可以被缓存以及存入到书签里,post不可以。 30 | * 编码类型不一样,get: `application/x-www-form-urlencoded`, post: `application/x-www-form-urlencoded`或`multipart/form-data`。 31 | -------------------------------------------------------------------------------- /计算机网络/TCP和UDP的区别.md: -------------------------------------------------------------------------------- 1 | #TCP和UDP的区别 2 | 3 | ### 1.区别 4 | 5 | 1. TCP是面向连接的,UDP是无连接的,即发送数据之前不需要建立连接. 6 | 2. TCP提供可靠的服务,通过TCP连接传送的数据:无差错,不丢失,不重复,且按序到达. UDP尽最大努力交付,即不保证可靠交互. 7 | Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。 8 | 9 | 3. UDP具有良好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信. 10 | 4. 每条TCP连接只能是点到点;UDP支持一对一,一对多,多对一,多对多的交互通信 11 | 5. TCP对系统资源要求较多,UDP对系统资源要求较少. 12 | 13 | ### 2.为什么UDP有时比TCP更有优势? 14 | UDP以其简单、传输快的优势,在越来越多场景下取代了TCP,如实时游戏。 15 | 16 | (1)网速的提升给UDP的稳定性提供可靠网络保障,丢包率很低,如果使用应用层重传,能够确保传输的可靠性。 17 | 18 | (2)TCP为了实现网络通信的可靠性,使用了复杂的拥塞控制算法,建立了繁琐的握手过程,由于TCP内置的系统协议栈中,极难对其进行改进。 19 | -------------------------------------------------------------------------------- /计算机网络/计算机网络体系结构.md: -------------------------------------------------------------------------------- 1 | ## 计算机网络体系结构 2 | 3 | ![](http://olg7c0d2n.bkt.clouddn.com/18-4-4/45615884.jpg) 4 | 5 | ### 五层协议 6 | 7 | 1.应用层:为特定应用程序提供数据传输服务,例如 HTTP、DNS 等。数据单位为报文。 8 | 9 | 2.运输层:提供的是进程间的通用数据传输服务。由于应用层协议很多,定义通用的运输层协议就可以支持不断增多的应用层协议。运输层包括两种协议:传输控制协议 TCP,提供面向连接、可靠的数据传输服务,数据单位为报文段;用户数据报协议 UDP,提供无连接、尽最大努力的数据传输服务,数据单位为用户数据报。TCP 主要提供完整性服务,UDP 主要提供及时性服务。 10 | 11 | 3.网络层:为主机之间提供数据传输服务,而运输层协议是为主机中的进程提供服务。网络层把运输层传递下来的报文段或者用户数据报封装成分组。 12 | 13 | 4.数据链路层:网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,链路层协议就是为同一链路的结点提供服务。数据链路层把网络层传来的分组封装成帧。 14 | 15 | 5.物理层:考虑的是怎样在传输媒体上传输数据比特流,而不是指具体的传输媒体。物理层的作用是尽可能屏蔽传输媒体和通信手段的差异,使数据链路层感觉不到这些差异。 -------------------------------------------------------------------------------- /计算机网络/趣谈网络协议/应用层/第18讲 DNS协议:网络世界的地址簿.md: -------------------------------------------------------------------------------- 1 | **第18讲 | DNS协议:网络世界的地址簿** 2 | 3 | **第18讲 DNS协议:网络世界的地址簿** 4 | 5 | -------------------------------------------------------------------------------- /计算机网络/趣谈网络协议/第2讲 为什么要学习网络协议.md: -------------------------------------------------------------------------------- 1 | # 协议三要素 2 | 语法、语义、顺序 3 | # 网络数据包结构 4 | Mac头 Ip头 Tcp头 Http头 数据体 5 | # 网络五层模型 6 | 1. 物理层:连接 7 | 2. 链路层:定位 8 | 3. 传输层:路由 9 | 4. 会话层:会话连接机制 10 | 5. 应用层:数据封装格式 -------------------------------------------------------------------------------- /计算机网络/趣谈网络协议/第3讲 ifconfig:最熟悉又陌生的命令行.md: -------------------------------------------------------------------------------- 1 | # ifconfig:最熟悉又陌生的命令行 2 | 3 | 在 Windows 上是 ipconfig,在 Linux 上是 ifconfig。 4 | 5 | IP 地址是一个网卡在网络世界的通讯地址,相当于我们现实世界的门牌号码。 6 | 7 | 如上输出的结果,10.100.122.2 就是一个 IP 地址。这个地址被点分隔为四个部分,每个部分 8 个 bit,所以 IP 地址总共是 32 位。 8 | 9 | ![](https://static001.geekbang.org/resource/image/0b/9e/0b32d6e35ff0bbc5d46cfb87f6669d9e.jpg) 10 | 11 | 在网络地址中,至少在当时设计的时候,对于 A、B、 C 类主要分两部分,前面一部分是网络号,后面一部分是主机号。 12 | 13 | ![](https://static001.geekbang.org/resource/image/e9/be/e9c59a4b2f0b804356759b10440ea7be.jpg) 14 | 15 | ## 无类型域间选路(CIDR) 16 | 17 | 于是有了一个折中的方式叫作无类型域间选路,简称CIDR。这种方式打破了原来设计的几类地址的做法,将 32 位的 IP 地址一分为二,前面是网络号,后面是主机号。从哪里分呢?你如果注意观察的话可以看到,10.100.122.2/24,这个 IP 地址中有一个斜杠,斜杠后面有个数字 24。这种地址表示形式,就是 CIDR。后面 24 的意思是,32 位中,前 24 位是网络号,后 8 位是主机号。 18 | 19 | 伴随着 CIDR 存在的,一个是广播地址,10.100.122.255。如果发送这个地址,所有 10.100.122 网络里面的机器都可以收到。另一个是子网掩码,255.255.255.0。 20 | 21 | 将子网掩码和 IP 地址进行 AND 计算。前面三个 255,转成二进制都是 1。1 和任何数值取 AND,都是原来数值,因而前三个数不变,为 10.100.122。后面一个 0,转换成二进制是 0,0 和任何数值取 AND,都是 0,因而最后一个数变为 0,合起来就是 10.100.122.0。这就是网络号。将子网掩码和 IP 地址按位计算 AND,就可得到网络号。 22 | 23 | 表格中的 192.168.0.x 是最常用的私有 IP 地址。你家里有 Wi-Fi,对应就会有一个 IP 地址。一般你家里地上网设备不会超过 256 个,所以 /24 基本就够了。有时候我们也能见到 /16 的 CIDR,这两种是最常见的,也是最容易理解的。 24 | 25 | 不需要将十进制转换为二进制 32 位,就能明显看出 192.168.0 是网络号,后面是主机号。而整个网络里面的第一个地址 192.168.0.1,往往就是你这个私有网络的出口地址。例如,你家里的电脑连接 Wi-Fi,Wi-Fi 路由器的地址就是 192.168.0.1,而 192.168.0.255 就是广播地址。一旦发送这个地址,整个 192.168.0 网络里面的所有机器都能收到。 26 | 27 | 举例:一个容易“犯错”的 CIDR 28 | 我们来看 16.158.165.91/22 这个 CIDR。求一下这个网络的第一个地址、子网掩码和广播地址。 29 | 30 | 你要是上来就写 16.158.165.1,那就大错特错了。 31 | 32 | /22 不是 8 的整数倍,不好办,只能先变成二进制来看。16.158 的部分不会动,它占了前 16 位。中间的 165,变为二进制为‭10100101‬。除了前面的 16 位,还剩 6 位。所以,这 8 位中前 6 位是网络号,16.158.<101001>,而 <01>.91 是机器号。 33 | 34 | 第一个地址是 16.158.<101001><00>.1,即 16.158.164.1。子网掩码是 255.255.<111111><00>.0,即 255.255.252.0。广播地址为 16.158.<101001><11>.255,即 16.158.167.255。 35 | 36 | ## MAC地址 37 | 38 | MAC 地址更像是身份证,是一个唯一的标识。MAC 地址是有一定定位功能的,只不过范围非常有限。先找大地点IP,再找小地点mac地址. 39 | 40 | IP 是地址,有定位功能;MAC 是身份证,无定位功能; 41 | 42 | IP 分公有的 IP 和私有的 IP。 43 | 44 | -------------------------------------------------------------------------------- /计算机网络/趣谈网络协议/第4讲 DHCP与PXE,IP是怎么来的,又是怎么没的.md: -------------------------------------------------------------------------------- 1 | # DHCP与PXE:IP是怎么来的,又是怎么没的 2 | 3 | ## 如何配置 IP 地址 4 | 5 | 使用 net-tools: 6 | ``` 7 | sudo ifconfig eth1 10.0.0.1/24 8 | sudo ifconfig eth1 up 9 | ``` 10 | 使用iproute2: 11 | ``` 12 | sudo ip addr add 10.0.0.1/24 dev eth1 13 | sudo if link set up eth1 14 | ``` 15 | 16 | ## 动态主机配置协议(DHCP) 17 | 18 | 通过这玩意儿去自动配置IP.有了这个协议,网络管理员就轻松多了。他只需要配置一段共享的 IP 地址。每一台新接入的机器都通过 DHCP 协议,来这个共享的 IP 地址里申请,然后自动配置好就可以了。等人走了,或者用完了,还回去,这样其他的机器也能用。 19 | 20 | 所以说,如果是数据中心里面的服务器,IP 一旦配置好,基本不会变,这就相当于买房自己装修。DHCP 的方式就相当于租房。你不用装修,都是帮你配置好的。你暂时用一下,用完退租就可以了。 21 | 22 | ## 解析 DHCP 的工作方式 23 | 24 | 当一台机器新加入一个网络的时候,肯定一脸懵,啥情况都不知道,只知道自己的 MAC 地址。怎么办?先吼一句,我来啦,有人吗?这时候的沟通基本靠“吼”。这一步,我们称为DHCP Discover。 25 | 26 | 如果一个网络管理员在网络里面配置了DHCP Server的话,他就相当于这些 IP 的管理员。他立刻能知道来了一个“新人”。这个时候,我们可以体会 MAC 地址唯一的重要性了。当一台机器带着自己的 MAC 地址加入一个网络的时候,MAC 是它唯一的身份,如果连这个都重复了,就没办法配置了。 27 | 28 | 只有 MAC 唯一,IP 管理员才能知道这是一个新人,需要租给它一个 IP 地址,这个过程我们称为DHCP Offer。同时,DHCP Server 为此客户保留为它提供的 IP 地址,从而不会为其他 DHCP 客户分配此 IP 地址。 29 | 30 | 如果有多个DHCP Server同时给一台新机器分配IP,那么这台机器一般会选择先到达的ip,然后将剩余的ip通知返回给提供者DHCP Server. 31 | 32 | ## IP 地址的收回和续租 33 | 34 | 35 | 既然是租房子,就是有租期的。租期到了,管理员就要将 IP 收回。 36 | 37 | 如果不用的话,收回就收回了。就像你租房子一样,如果还要续租的话,不能到了时间再续租,而是要提前一段时间给房东说。DHCP 也是这样。 38 | 39 | 客户机会在租期过去 50% 的时候,直接向为其提供 IP 地址的 DHCP Server 发送 DHCP request 消息包。客户机接收到该服务器回应的 DHCP ACK 消息包,会根据包中所提供的新的租期以及其他已经更新的 TCP/IP 参数,更新自己的配置。这样,IP 租用更新就完成了。 40 | 41 | ## 预启动执行环境(PXE) 42 | 43 | 那我们安装操作系统的过程,只能插在 BIOS 启动之后了。因为没安装系统之前,连启动扇区都没有。因而这个过程叫做预启动执行环境(Pre-boot Execution Environment),简称PXE。 44 | 45 | DHCP Server 会给PXE分配IP地址 46 | 47 | ## 解析 PXE 的工作过程 48 | 49 | 首先,启动 PXE 客户端。第一步是通过 DHCP 协议告诉 DHCP Server,我刚来,一穷二白,啥都没有。DHCP Server 便租给它一个 IP 地址,同时也给它 PXE 服务器的地址、启动文件 pxelinux.0。 50 | 51 | 其次,PXE 客户端知道要去 PXE 服务器下载这个文件后,就可以初始化机器。于是便开始下载,下载的时候使用的是 TFTP 协议。所以 PXE 服务器上,往往还需要有一个 TFTP 服务器。PXE 客户端向 TFTP 服务器请求下载这个文件,TFTP 服务器说好啊,于是就将这个文件传给它。 52 | 53 | 然后,PXE 客户端收到这个文件后,就开始执行这个文件。这个文件会指示 PXE 客户端,向 TFTP 服务器请求计算机的配置信息 pxelinux.cfg。TFTP 服务器会给 PXE 客户端一个配置文件,里面会说内核在哪里、initramfs 在哪里。PXE 客户端会请求这些文件。 54 | 55 | 最好,启动 Linux 内核。一旦启动了操作系统,以后就啥都好办了。 56 | 57 | ![](https://static001.geekbang.org/resource/image/6e/a4/6e69007db3fc68ff6da8496266abf6a4.jpg) 58 | 59 | ## 小结 60 | 61 | 好了,这一节就到这里了。我来总结一下今天的内容: 62 | 63 | DHCP 协议主要是用来给客户租用 IP 地址,和房产中介很像,要商谈、签约、续租,广播还不能“抢单”; 64 | 65 | DHCP 协议能给客户推荐“装修队”PXE,能够安装操作系统,这个在云计算领域大有用处。 -------------------------------------------------------------------------------- /计算机网络/趣谈网络协议/第5讲 从物理层到MAC层:如何在宿舍里自己组网玩联机游戏.md: -------------------------------------------------------------------------------- 1 | #第5讲 | 从物理层到MAC层:如何在宿舍里自己组网玩联机游戏? 2 | 3 | ## 第一层(物理层) 4 | 5 | >使用路由器,是在第三层上。我们先从第一层物理层开始说。 6 | 7 | 两台电脑通过网线连接,构成最小的局域网,即LAN.必须配置成一个网络,否则不通.两台电脑的网络包,包含MAC层,IP层要封装了MAC层才能放入物理层. 8 | 9 | 有一个叫作Hub的东西,也就是集线器。这种设备有多个口,可以将宿舍里的多台电脑连接起来。但是,和交换机不同,集线器没有大脑,它完全在物理层工作。它会将自己收到的每一个字节,都复制到其他端口上去。这是第一层物理层联通的方案。 10 | 11 | ## 第二层(数据链路层) 12 | 13 | Hub 采取的是广播的模式,如果每一台电脑发出的包,宿舍的每个电脑都能收到,那就麻烦了。这就需要解决几个问题: 14 | 15 | - 这个包是发给谁的?谁应该接收? 16 | - 大家都在发,会不会产生混乱?有没有谁先发、谁后发的规则? 17 | - 如果发送的时候出现了错误,怎么办? 18 | 19 | 这几个问题,都是第二层,数据链路层,也即 MAC 层要解决的问题。MAC的全称是Medium Access Control,即媒体访问控制。控制什么呢?其实就是控制在往媒体上发数据的时候,谁先发、谁后发的问题。防止发生混乱。这解决的是第二个问题。这个问题中的规则,学名叫多路访问。 20 | 21 | 解决第一个问题就牵扯到第二层的网络包格式。对于以太网,第二层的最开始,就是目标的 MAC 地址和源的 MAC 地址。 22 | 23 | 有了这个目标 MAC 地址,数据包在链路上广播,MAC 的网卡才能发现,这个包是给它的。MAC 的网卡把包收进来,然后打开 IP 包,发现 IP 地址也是自己的,再打开 TCP 包,发现端口是自己,也就是 80,而 nginx 就是监听 80。 24 | 25 | 于是将请求提交给 nginx,nginx 返回一个网页。然后将网页需要发回请求的机器。然后层层封装,最后到 MAC 层。因为来的时候有源 MAC 地址,返回的时候,源 MAC 就变成了目标 MAC,再返给请求的机器。 26 | 27 | 对于以太网,第二层的最后面是CRC,也就是循环冗余检测。通过 XOR 异或的算法,来计算整个包是否在发送的过程中出现了错误,主要解决第三个问题。 28 | 29 | 这里还有一个没有解决的问题,当源机器知道目标机器的时候,可以将目标地址放入包里面,如果不知道呢?一个广播的网络里面接入了 N 台机器,我怎么知道每个 MAC 地址是谁呢?这就是ARP 协议,也就是已知 IP 地址,求 MAC 地址的协议。 30 | 31 | ![](https://static001.geekbang.org/resource/image/17/3d/17ac2f46ef531e2b4380300f10267e3d.jpg) 32 | 33 | ## 局域网 34 | 35 | Hub 是广播的,不管某个接口是否需要,所有的 Bit 都会被发送出去,然后让主机来判断是不是需要。这种方式路上的车少就没问题,车一多,产生冲突的概率就提高了。而且把不需要的包转发过去,纯属浪费。看来 Hub 这种不管三七二十一都转发的设备是不行了,需要点儿智能的。因为每个口都只连接一台电脑,这台电脑又不怎么换 IP 和 MAC 地址,只要记住这台电脑的 MAC 地址,如果目标 MAC 地址不是这台电脑的,这个口就不用转发了。 36 | 37 | 谁能知道目标 MAC 地址是否就是连接某个口的电脑的 MAC 地址呢?这就需要一个能把 MAC 头拿下来,检查一下目标 MAC 地址,然后根据策略转发的设备,按第二节课中讲过的,这个设备显然是个二层设备,我们称为交换机。 38 | 39 | 交换机怎么知道每个口的电脑的 MAC 地址呢?这需要交换机会学习。一台 MAC1 电脑将一个包发送给另一台 MAC2 电脑,当这个包到达交换机的时候,一开始交换机也不知道 MAC2 的电脑在哪个口,所以没办法,它只能将包转发给除了来的那个口之外的其他所有的口。但是,这个时候,交换机会干一件非常聪明的事情,就是交换机会记住,MAC1 是来自一个明确的口。以后有包的目的地址是 MAC1 的,直接发送到这个口就可以了。 40 | 41 | 当交换机作为一个关卡一样,过了一段时间之后,就有了整个网络的一个结构了,这个时候,基本上不用广播了,全部可以准确转发。当然,每个机器的 IP 地址会变,所在的口也会变,因而交换机上的学习的结果,我们称为转发表,是有一个过期时间的。 42 | 43 | ## 小结 44 | 45 | 第一,MAC 层是用来解决多路访问的堵车问题的; 46 | 47 | 第二,ARP 是通过吼的方式来寻找目标 MAC 地址的,吼完之后记住一段时间,这个叫作缓存; 48 | 49 | 第三,交换机是有 MAC 地址学习能力的,学完了它就知道谁在哪儿了,不用广播了。 -------------------------------------------------------------------------------- /计算机网络/趣谈网络协议/第7讲 ICMP与ping_投石问路的侦察兵.md: -------------------------------------------------------------------------------- 1 | # 第7讲 | ICMP与ping 2 | 3 | ## ICMP 协议的格式 4 | 5 | > ping 是基于 ICMP 协议工作的。ICMP全称Internet Control Message Protocol,就是互联网控制报文协议。 6 | 7 | 网络包在异常复杂的网络环境中传输时,常常会遇到各种各样的问题。当遇到问题的时候,总不能“死个不明不白”,要传出消息来,报告情况,这样才可以调整传输策略。ICMP 报文是封装在 IP 包里面的。因为传输指令的时候,肯定需要源地址和目标地址。它本身非常简单。因为作为侦查兵,要轻装上阵,不能携带大量的包袱 8 | 9 | ICMP 报文有很多的类型,不同的类型有不同的代码。最常用的类型是主动请求为 8,主动请求的应答为 0。 10 | 11 | ## 查询报文类型 12 | 13 | 所以,ping 发的包也是符合 ICMP 协议格式的,只不过它在后面增加了自己的格式。 14 | 15 | 对 ping 的主动请求,进行网络抓包,称为ICMP ECHO REQUEST。同理主动请求的回复,称为ICMP ECHO REPLY。比起原生的 ICMP,这里面多了两个字段,一个是标识符。 16 | 17 | ## 差错报文类型 18 | 19 | 当然也有另外一种方式,就是差错报文。 20 | 我举几个 ICMP 差错报文的例子:终点不可达为 3,源抑制为 4,超时为 11,重定向为 5。 21 | 22 | - 第一种是终点不可达。 23 | - 第二种是源站抑制,也就是让源站放慢发送速度。 24 | - 第三种是时间超时,也就是超过网络包的生存时间还是没到。 25 | - 第四种是路由重定向,也就是让下次发给另一个路由器。 26 | - 差错报文的结构相对复杂一些。除了前面还是 IP,ICMP 的前 8 字节不变,后面则跟上出错的那个 IP 包的 IP 头和 IP 正文的前 8 个字节。 27 | 28 | ## 查询报文类型的使用 29 | 30 | ![](https://static001.geekbang.org/resource/image/e5/fc/e5270427819fc51c88e81a5c1cc4b8fc.jpg) 31 | 32 | ping 命令执行的时候,源主机首先会构建一个 ICMP 请求数据包,ICMP 数据包内包含多个字段。最重要的是两个,第一个是类型字段,对于请求数据包而言该字段为 8;另外一个是顺序号,主要用于区分连续 ping 的时候发出的多个数据包。每发出一个请求数据包,顺序号会自动加 1。为了能够计算往返时间 RTT,它会在报文的数据部分插入发送时间。 33 | 34 | 然后,由 ICMP 协议将这个数据包连同地址 192.168.1.2 一起交给 IP 层。IP 层将以 192.168.1.2 作为目的地址,本机 IP 地址作为源地址,加上一些其他控制信息,构建一个 IP 数据包。 35 | 36 | ## Traceroute:差错报文类型的使用 37 | 38 | > 有一个程序 Traceroute,是个“大骗子”。它会使用 ICMP 的规则,故意制造一些能够产生错误的场景。 39 | 40 | 41 | 所以,Traceroute 的第一个作用就是故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。Traceroute 的参数指向某个目的 IP 地址,它会发送一个 UDP 的数据包。将 TTL 设置成 1,也就是说一旦遇到一个路由器或者一个关卡,就表示它“牺牲”了。 42 | 43 | ## 小结 44 | 45 | - ICMP 相当于网络世界的侦察兵。我讲了两种类型的 ICMP 报文,一种是主动探查的查询报文,一种异常报告的差错报文; 46 | - ping 使用查询报文,Traceroute 使用差错报文。 47 | --------------------------------------------------------------------------------