Showing preview only (5,119K chars total). Download the full file or copy to clipboard to get everything.
Repository: pengMaster/BestNote
Branch: master
Commit: 941811623440
Files: 740
Total size: 4.7 MB
Directory structure:
gitextract_bgwjn77o/
├── LICENSE
├── README.md
└── docs/
├── .nojekyll
├── android/
│ ├── Android-Interview/
│ │ ├── .gitignore
│ │ ├── Activity/
│ │ │ ├── Activity Task和Process.md
│ │ │ ├── App优雅退出.md
│ │ │ ├── README.md
│ │ │ ├── onCreate源码分析.md
│ │ │ ├── onSaveInstanceState源码内核分析.md
│ │ │ ├── 为什么service里面startActivity抛异常.md
│ │ │ ├── 深入理解Activity启动流程.md
│ │ │ ├── 深刻剖析activity启动模式-1.md
│ │ │ ├── 深刻剖析activity启动模式-2.md
│ │ │ └── 深刻剖析activity启动模式-3.md
│ │ ├── Android/
│ │ │ ├── Android基础面试核心内容.md
│ │ │ ├── Android视频教程.md
│ │ │ ├── Android面试精华题目总结.md
│ │ │ ├── Android面试重点.md
│ │ │ ├── Android面试题-1.md
│ │ │ ├── Android面试题-2.md
│ │ │ ├── Android高级面试10大开源框架源码解析.md
│ │ │ ├── BAT大咖助力全面升级Android面试.md
│ │ │ ├── README.md
│ │ │ ├── 平台架构.md
│ │ │ └── 接口安全.md
│ │ ├── HR/
│ │ │ ├── README.md
│ │ │ ├── 人事面试宝典.md
│ │ │ ├── 人事面试宝典一之自我介绍.md
│ │ │ └── 人事面试宝典二之离职.md
│ │ ├── Java/
│ │ │ ├── 115个Java面试题及回答.md
│ │ │ ├── 66道经典的Java基础面试题集锦.md
│ │ │ ├── J2SE基础面试核心内容.md
│ │ │ ├── J2SE高级面试核心内容.md
│ │ │ ├── Java面试题-1.md
│ │ │ ├── Java面试题-2.md
│ │ │ ├── Java高级软件工程师面试考纲.md
│ │ │ ├── README.md
│ │ │ ├── 数据库求差.md
│ │ │ └── 深拷贝浅拷贝.md
│ │ ├── README.md
│ │ ├── SUMMARY.md
│ │ ├── Service/
│ │ │ ├── Android面试题-Service.md
│ │ │ ├── Android面试题-Service不死之身.md
│ │ │ ├── IntentService源码分析.md
│ │ │ └── README.md
│ │ ├── book.json
│ │ ├── 开发遇到的问题/
│ │ │ ├── Context原理分析.md
│ │ │ ├── README.md
│ │ │ ├── ViewPager和Fragment使用过程中会遇到哪些问题.md
│ │ │ ├── 手把手教你如何解决as jar包冲突.md
│ │ │ ├── 机型适配之痛.md
│ │ │ ├── 终极解决ViewPager.setCurrentItem中间页面过多解决方案.md
│ │ │ ├── 解决字体适配.md
│ │ │ ├── 软键盘顶出去解决方案.md
│ │ │ └── 迭代开发的时候如何向前兼容新旧接口?.md
│ │ ├── 性能优化/
│ │ │ ├── Android应用UI性能分析.md
│ │ │ ├── App应用启动分析与优化.md
│ │ │ ├── README.md
│ │ │ ├── 与IPC机制相关面试题.md
│ │ │ ├── 与性能优化相关试题一.md
│ │ │ ├── 与性能优化相关试题三.md
│ │ │ ├── 与性能优化相关试题二.md
│ │ │ └── 内存泄漏监测.md
│ │ ├── 源码分析/
│ │ │ ├── Android源码编译实现静默安装和静默偷拍.md
│ │ │ ├── README.md
│ │ │ ├── Volley源码剖析.md
│ │ │ ├── okhttp内核剖析.md
│ │ │ └── 注解框架内部实现原理.md
│ │ ├── 登陆注册/
│ │ │ ├── Oauth的实现原理.md
│ │ │ ├── README.md
│ │ │ ├── Token的实际意义.md
│ │ │ └── 微信扫码登录内部实现原理.md
│ │ ├── 经验分享/
│ │ │ ├── 2016年4月某公司面试题及面试流程.md
│ │ │ ├── 2017届实习生招聘面经.md
│ │ │ ├── Andorid-15k+的面试题.md
│ │ │ ├── Android 暑期实习生面试经验谈.md
│ │ │ ├── Android 曲折的求职之路.md
│ │ │ ├── BAT无线工程师面试流程详细解析.md
│ │ │ ├── README.md
│ │ │ ├── 一个五年Android开发者百度、阿里、聚美、映客的面试心经.md
│ │ │ ├── 一个程序员的血泪史.md
│ │ │ ├── 互联网公司面试经验总结.md
│ │ │ ├── 互联网巨头BAT3内部员工的真实状况.md
│ │ │ ├── 史上最全 Android 面试资料集合.md
│ │ │ ├── 国内一线互联网公司内部面试题库.md
│ │ │ ├── 工作三年后,我选择离开腾讯.md
│ │ │ ├── 我为什么离开锤子科技?.md
│ │ │ ├── 我为什么要离开华为?.md
│ │ │ ├── 扫清Android面试障碍.md
│ │ │ ├── 技术硬碰硬—阳哥带你玩转上海Android招聘市场.md
│ │ │ ├── 杭州找 Android 工作的点点滴滴.md
│ │ │ ├── 给培训班出来的一点不成熟的小建议.md
│ │ │ ├── 腾讯公司程序员面试题及答案详解.md
│ │ │ ├── 阿里+百度+CVTE面经合集.md
│ │ │ └── 面试心得与总结:BAT、网易、蘑菇街 .md
│ │ ├── 网络编程/
│ │ │ ├── Android客户端和服务端如何使用Token和Session.md
│ │ │ ├── README.md
│ │ │ ├── 推送原理.md
│ │ │ ├── 简单阐述一下及时推送原理?.md
│ │ │ └── 阐述一下对XMPP协议理解以及优缺点?.md
│ │ └── 面试技巧/
│ │ ├── README.md
│ │ ├── 我在面试中最喜欢问开发者的问题,和回答思路.md
│ │ ├── 程序员面试宝典.md
│ │ └── 罗永浩新东方万字求职信.md
│ ├── AndroidNote/
│ │ ├── AdavancedPart/
│ │ │ ├── 1.热修复实现(一).md
│ │ │ ├── 2.热修复实现(二).md
│ │ │ ├── 3.热修复_addAssetPath不同版本区别原因(三).md
│ │ │ ├── ART与Dalvik.md
│ │ │ ├── Android WorkManager.md
│ │ │ ├── Android6.0权限系统.md
│ │ │ ├── Android卸载反馈.md
│ │ │ ├── Android启动模式详解.md
│ │ │ ├── Android开发不申请权限来使用对应功能.md
│ │ │ ├── Android开发中的MVP模式详解.md
│ │ │ ├── ApplicationId vs PackageName.md
│ │ │ ├── BroadcastReceiver安全问题.md
│ │ │ ├── ConstraintLaayout简介.md
│ │ │ ├── Handler导致内存泄露分析.md
│ │ │ ├── Library项目中资源id使用case时报错.md
│ │ │ ├── Mac下配置adb及Android命令.md
│ │ │ ├── MaterialDesign使用.md
│ │ │ ├── RecyclerView专题.md
│ │ │ ├── 如何让Service常驻内存.md
│ │ │ ├── 屏幕适配之百分比方案详解.md
│ │ │ ├── 布局优化.md
│ │ │ ├── 性能优化.md
│ │ │ ├── 注解使用.md
│ │ │ └── 通过Hardware Layer提高动画性能.md
│ │ ├── AndroidStudioCourse/
│ │ │ ├── Android Studio你可能不知道的操作.md
│ │ │ ├── AndroidStudio中进行ndk开发.md
│ │ │ ├── AndroidStudio使用教程(第一弹).md
│ │ │ ├── AndroidStudio使用教程(第七弹).md
│ │ │ ├── AndroidStudio使用教程(第三弹).md
│ │ │ ├── AndroidStudio使用教程(第二弹).md
│ │ │ ├── AndroidStudio使用教程(第五弹).md
│ │ │ ├── AndroidStudio使用教程(第六弹).md
│ │ │ ├── AndroidStudio使用教程(第四弹).md
│ │ │ └── AndroidStudio提高Build速度.md
│ │ ├── Android基础/
│ │ │ ├── Activity详细解析.md
│ │ │ ├── Android-SQLite的基本使用.md
│ │ │ ├── Android中相机与相册的详细使用.md
│ │ │ ├── Android异步任务机制之AsycTask.md
│ │ │ ├── Android数据存储的五种方式.md
│ │ │ ├── Android获取SHA1.md
│ │ │ ├── Android跟随手指移动的view.md
│ │ │ ├── BroadcastReceiver详细解析.md
│ │ │ ├── ContentProvider实例详解.md
│ │ │ ├── Handler,Looper,MessageQueue关系.md
│ │ │ ├── IntentService详细解析.md
│ │ │ ├── RecyclerView的简介.md
│ │ │ ├── Service详细解析.md
│ │ │ ├── tablayout记录.md
│ │ │ ├── test.kt
│ │ │ └── 图片缓存原理.md
│ │ ├── Android开源框架相关/
│ │ │ ├── Android当下最流行的开源框架总结.md
│ │ │ ├── Android黑科技——ButterKnifeZelezny.md
│ │ │ ├── Picasso-android-load-image-layout.md
│ │ │ ├── RxJava+retrofit2实现安卓中网络操作.md
│ │ │ ├── 一款Android的Log、Toast的库.md
│ │ │ └── 动态申请权限库:easypermissions使用与源码解析.md
│ │ ├── Android性能优化相关/
│ │ │ └── LeakCanary工作过程以及原理.md
│ │ ├── Android打包相关/
│ │ │ ├── Android发布sdk到jcenter.md
│ │ │ └── Android将library打包成jar文件或aar文件.md
│ │ ├── Android报错记录/
│ │ │ ├── Android报错-Manifest merger failed with multiple errors, see logs.md
│ │ │ └── Android报错2.md
│ │ ├── Android编译器相关/
│ │ │ ├── AndroidStudio使用教程(第一弹).md
│ │ │ ├── AndroidStudio使用教程(第七弹).md
│ │ │ ├── AndroidStudio使用教程(第三弹).md
│ │ │ ├── AndroidStudio使用教程(第二弹).md
│ │ │ ├── AndroidStudio使用教程(第五弹).md
│ │ │ ├── AndroidStudio使用教程(第六弹).md
│ │ │ └── AndroidStudio使用教程(第四弹).md
│ │ ├── Android自定义View/
│ │ │ ├── Android事件分发机制.md
│ │ │ ├── PathMeasure.md
│ │ │ ├── 三阶贝塞尔曲线.md
│ │ │ ├── 二阶贝塞尔曲线.md
│ │ │ ├── 自定义ViewGroup入门.md
│ │ │ ├── 自定义View——CameraView.md
│ │ │ ├── 自定义View——CheckView.md
│ │ │ ├── 自定义View——CircleView.md
│ │ │ ├── 自定义View——FlowLayout.md
│ │ │ ├── 自定义View——PieView.md
│ │ │ ├── 自定义View入门.md
│ │ │ └── 自定义view——sideslipListView.md
│ │ ├── Android进阶/
│ │ │ ├── AndroidStudio导入工程一直在Building的解决方案.md
│ │ │ ├── Android中的动画.md
│ │ │ ├── Android内存泄漏总结.md
│ │ │ ├── Android性能优化.md
│ │ │ ├── Android项目总结.md
│ │ │ ├── Android项目总结2.md
│ │ │ ├── Android项目总结3.md
│ │ │ ├── Handler引起的内存泄漏以及分析.md
│ │ │ ├── MVP+RxJava+Retrofit2+Dagger实战.md
│ │ │ ├── Recyclerview和Listview的异同.md
│ │ │ ├── iterm2+vim打造完美终端.md
│ │ │ ├── jvm-serializers.md
│ │ │ ├── 基于OTP算法的双向认证.md
│ │ │ ├── 检查app是否有推送权限.md
│ │ │ ├── 深入了解MVXX模式.md
│ │ │ └── 自定义RadioGroup.md
│ │ ├── Android面试相关/
│ │ │ ├── Android5.0-6.0-7.0新特性.md
│ │ │ ├── Android中常见面试题.md
│ │ │ ├── Android中弱引用与软引用.md
│ │ │ ├── Android图片三级缓存.md
│ │ │ ├── Android推送实现原理.md
│ │ │ ├── Asset目录与res目录的区别.md
│ │ │ ├── JSON的定义.md
│ │ │ ├── Java中Error和Exception.md
│ │ │ ├── ListView性能优化.md
│ │ │ ├── Service保活.md
│ │ │ ├── 如何实现Activity切换的动画.md
│ │ │ ├── 如何提高Activity启动速度.md
│ │ │ ├── 如何终止App的运行.md
│ │ │ └── 面试题.md
│ │ ├── AppPublish/
│ │ │ ├── Android应用发布.md
│ │ │ ├── Zipalign优化.md
│ │ │ └── 使用Jenkins实现自动化打包.md
│ │ ├── ArchitectureComponents/
│ │ │ ├── 1.简介(一).md
│ │ │ ├── 2.集成(二).md
│ │ │ ├── 3.Lifecycle(三).md
│ │ │ ├── 4.LiveData(四).md
│ │ │ ├── 5.ViewModel(五).md
│ │ │ ├── 6.Room(六).md
│ │ │ └── 7.PagingLibrary(七).md
│ │ ├── BasicKnowledge/
│ │ │ ├── Android入门介绍.md
│ │ │ ├── Android动画.md
│ │ │ ├── Android四大组件之ContentProvider.md
│ │ │ ├── Android四大组件之Service.md
│ │ │ ├── Android基础面试题.md
│ │ │ ├── Android编码规范.md
│ │ │ ├── Ant打包.md
│ │ │ ├── Bitmap优化.md
│ │ │ ├── Fragment专题.md
│ │ │ ├── Home键监听.md
│ │ │ ├── HttpClient执行Get和Post请求.md
│ │ │ ├── JNI_C语言基础.md
│ │ │ ├── JNI基础.md
│ │ │ ├── ListView专题.md
│ │ │ ├── Parcelable及Serializable.md
│ │ │ ├── PopupWindow细节.md
│ │ │ ├── SDK Manager无法更新的问题.md
│ │ │ ├── Scroller简介.md
│ │ │ ├── ScrollingTabs.md
│ │ │ ├── Selector使用.md
│ │ │ ├── SlidingMenu.md
│ │ │ ├── String格式化.md
│ │ │ ├── TextView跑马灯效果.md
│ │ │ ├── WebView总结.md
│ │ │ ├── Widget(窗口小部件).md
│ │ │ ├── Wifi状态监听.md
│ │ │ ├── XmlPullParser.md
│ │ │ ├── adb logcat使用简介.md
│ │ │ ├── 下拉刷新ListView.md
│ │ │ ├── 代码混淆.md
│ │ │ ├── 任务管理器(ActivityManager).md
│ │ │ ├── 修改系统组件样式.md
│ │ │ ├── 内存泄漏.md
│ │ │ ├── 多线程断点下载.md
│ │ │ ├── 安全退出应用程序.md
│ │ │ ├── 屏幕适配.md
│ │ │ ├── 应用后台唤醒后数据的刷新.md
│ │ │ ├── 应用安装.md
│ │ │ ├── 开发中Log的管理.md
│ │ │ ├── 开发中异常的处理.md
│ │ │ ├── 快捷方式工具类.md
│ │ │ ├── 手机摇晃.md
│ │ │ ├── 搜索框.md
│ │ │ ├── 数据存储.md
│ │ │ ├── 文件上传.md
│ │ │ ├── 来电号码归属地提示框.md
│ │ │ ├── 来电监听及录音.md
│ │ │ ├── 横向ListView.md
│ │ │ ├── 滑动切换Activity(GestureDetector).md
│ │ │ ├── 病毒.md
│ │ │ ├── 知识大杂烩.md
│ │ │ ├── 短信广播接收者.md
│ │ │ ├── 程序的启动、卸载和分享.md
│ │ │ ├── 竖着的Seekbar.md
│ │ │ ├── 自定义Toast.md
│ │ │ ├── 自定义控件.md
│ │ │ ├── 自定义状态栏通知.md
│ │ │ ├── 自定义背景.md
│ │ │ ├── 获取位置(LocationManager).md
│ │ │ ├── 获取应用程序缓存及一键清理.md
│ │ │ ├── 获取手机中所有安装的程序.md
│ │ │ ├── 获取手机及SD卡可用存储空间.md
│ │ │ ├── 获取联系人.md
│ │ │ ├── 读取用户logcat日志.md
│ │ │ ├── 资源文件拷贝的三种方式.md
│ │ │ ├── 超级管理员(DevicePoliceManager).md
│ │ │ ├── 锁屏以及解锁监听.md
│ │ │ ├── 零权限上传数据.md
│ │ │ ├── 音量及屏幕亮度调节.md
│ │ │ └── 黑名单挂断电话及删除电话记录.md
│ │ ├── Dagger2/
│ │ │ ├── 1.Dagger2简介(一).md
│ │ │ ├── 2.Dagger2入门demo(二).md
│ │ │ ├── 3.Dagger2入门demo扩展(三).md
│ │ │ ├── 4.Dagger2单例(四).md
│ │ │ ├── 5.Dagger2Lay和Provider(五).md
│ │ │ ├── 6.Dagger2Android示例代码(六).md
│ │ │ ├── 7.Dagger2之dagger-android(七).md
│ │ │ ├── 8.Dagger2与MVP(八).md
│ │ │ └── 9.Dagger2原理分析(九).md
│ │ ├── Git/
│ │ │ └── git详细教程.md
│ │ ├── Go/
│ │ │ └── Go的练习代码.md
│ │ ├── Gradle&Maven/
│ │ │ ├── Gradle专题.md
│ │ │ └── 发布library到Maven仓库.md
│ │ ├── IOSNote/
│ │ │ └── Ios上架app需要的图标尺寸.md
│ │ ├── IPC.md
│ │ ├── ImageLoaderLibrary/
│ │ │ ├── Glide简介(上).md
│ │ │ ├── Glide简介(下).md
│ │ │ └── 图片加载库比较.md
│ │ ├── JavaKnowledge/
│ │ │ ├── Base64加密.md
│ │ │ ├── Git简介.md
│ │ │ ├── HashMap实现原理分析.md
│ │ │ ├── Http与Https的区别.md
│ │ │ ├── JVM垃圾回收机制.md
│ │ │ ├── Java基础面试题.md
│ │ │ ├── MD5加密.md
│ │ │ ├── MVC与MVP及MVVM.md
│ │ │ ├── RMB大小写转换.md
│ │ │ ├── Top-K问题.md
│ │ │ ├── Vim使用教程.md
│ │ │ ├── hashCode与equals.md
│ │ │ ├── volatile和Synchronized区别.md
│ │ │ ├── 八种排序算法.md
│ │ │ ├── 剑指Offer(上).md
│ │ │ ├── 剑指Offer(下).md
│ │ │ ├── 动态代理.md
│ │ │ ├── 单例的最佳实现方式.md
│ │ │ ├── 原子性、可见性以及有序性.md
│ │ │ ├── 常用命令行大全.md
│ │ │ ├── 常见算法.md
│ │ │ ├── 强引用、软引用、弱引用、虚引用.md
│ │ │ ├── 数据加密及解密.md
│ │ │ ├── 数据结构.md
│ │ │ ├── 死锁.md
│ │ │ ├── 生产者消费者.md
│ │ │ ├── 算法的复杂度.md
│ │ │ ├── 线程池简介.md
│ │ │ ├── 网络请求相关内容总结.md
│ │ │ ├── 获取今后多少天后的日期.md
│ │ │ └── 设计模式.md
│ │ ├── JavaNote/
│ │ │ ├── Javaee/
│ │ │ │ └── Spring-boot入门.md
│ │ │ ├── Java相关/
│ │ │ │ ├── ArrayList、LinkedList、Vector的异同.md
│ │ │ │ ├── Des加密算法.md
│ │ │ │ ├── HashTable和HashMap的异同.md
│ │ │ │ ├── JVM类加载器.md
│ │ │ │ ├── JVM虚拟机基础知识.md
│ │ │ │ ├── Java中Error和Exception.md
│ │ │ │ ├── Java利用ExecutorService实现同步执行大量线程.md
│ │ │ │ ├── Java利用listener实现回调,即观察者模式.md
│ │ │ │ ├── Java回调的原理与实现.md
│ │ │ │ ├── Java基础知识.md
│ │ │ │ ├── Java注解的编写与Java的反射机制.md
│ │ │ │ ├── 发布jar包到Maven中央仓库.md
│ │ │ │ └── 面向对象的六大原则以及常见的十七种设计模式.md
│ │ │ └── 设计模式相关/
│ │ │ ├── 单例模式.md
│ │ │ ├── 单例模式的四种实现方式.md
│ │ │ ├── 观察者模式.md
│ │ │ └── 设计模式概括.md
│ │ ├── KotlinCourse/
│ │ │ ├── .idea/
│ │ │ │ ├── KotlinCourse.iml
│ │ │ │ ├── misc.xml
│ │ │ │ ├── modules.xml
│ │ │ │ └── workspace.xml
│ │ │ ├── Kotlin学习教程(一).md
│ │ │ ├── Kotlin学习教程(七).md
│ │ │ ├── Kotlin学习教程(三).md
│ │ │ ├── Kotlin学习教程(九).md
│ │ │ ├── Kotlin学习教程(二).md
│ │ │ ├── Kotlin学习教程(五).md
│ │ │ ├── Kotlin学习教程(八).md
│ │ │ ├── Kotlin学习教程(六).md
│ │ │ ├── Kotlin学习教程(十).md
│ │ │ └── Kotlin学习教程(四).md
│ │ ├── Kotlin相关/
│ │ │ └── Kotlin-for-android.md
│ │ ├── Linux/
│ │ │ └── Android-GitLabCi配置.md
│ │ ├── MacNote/
│ │ │ ├── Mac平台重新设置MySQL的root密码.md
│ │ │ ├── SSH原理与应用.md
│ │ │ ├── mac上常用命令.md
│ │ │ ├── mac本地生成ssh-key.md
│ │ │ ├── mac终端与服务器保持连接.md
│ │ │ ├── nodejs与npm的更新.md
│ │ │ ├── paw-for-mac.md
│ │ │ ├── 一些mac上面安装环境的指令.md
│ │ │ ├── 如何在mac上安装java1-8.md
│ │ │ └── 项目中遇到的单词.md
│ │ ├── READMENote.md
│ │ ├── ReactNative相关/
│ │ │ ├── React Native 的ES5 ES6写法对照表.md
│ │ │ ├── ReactNative入门.md
│ │ │ ├── ReactNative利用CodePush实现热更新.md
│ │ │ ├── ReactNative报错记录.md
│ │ │ ├── ReactNative调试心得.md
│ │ │ ├── Touchable系列组建讲解.md
│ │ │ └── 短信验证码倒计时控件.md
│ │ ├── RxJavaPart/
│ │ │ ├── 1.RxJava详解(一).md
│ │ │ ├── 2.RxJava详解(二).md
│ │ │ ├── 3.RxJava详解(三).md
│ │ │ ├── 4.RxJava详解之执行原理(四).md
│ │ │ ├── 5.RxJava详解之操作符执行原理(五).md
│ │ │ ├── 6.RxJava详解之线程调度原理(六).md
│ │ │ └── 7.RxJava系列全家桶.md
│ │ ├── ScriptNote/
│ │ │ ├── GitHub基础操作.md
│ │ │ ├── 一篇文章学懂Shell脚本.md
│ │ │ ├── 封装一些GitHub常用命令.md
│ │ │ └── 简单的Shell脚本.md
│ │ ├── SourceAnalysis/
│ │ │ ├── Activity启动过程.md
│ │ │ ├── Activity界面绘制过程详解.md
│ │ │ ├── Android Touch事件分发详解.md
│ │ │ ├── AsyncTask详解.md
│ │ │ ├── InstantRun详解.md
│ │ │ ├── ListView源码分析.md
│ │ │ ├── Netowork/
│ │ │ │ ├── HttpURLConnection与HttpClient.md
│ │ │ │ ├── HttpURLConnection详解.md
│ │ │ │ ├── Retrofit详解(上).md
│ │ │ │ ├── Retrofit详解(下).md
│ │ │ │ ├── Volley源码分析.md
│ │ │ │ └── volley-retrofit-okhttp之我们该如何选择网路框架.md
│ │ │ ├── VideoView源码分析.md
│ │ │ ├── View绘制过程详解.md
│ │ │ ├── butterknife源码详解.md
│ │ │ └── 自定义View详解.md
│ │ ├── Tools&Library/
│ │ │ ├── Android开发工具及类库.md
│ │ │ ├── Github个人主页绑定域名.md
│ │ │ ├── MAT内存分析.md
│ │ │ ├── Markdown学习手册.md
│ │ │ ├── 性能优化相关工具.md
│ │ │ ├── 目前流行的开发组合.md
│ │ │ └── 调试平台Flipper.md
│ │ ├── VideoDevelopment/
│ │ │ ├── Android WebRTC简介.md
│ │ │ ├── Android音视频开发.md
│ │ │ ├── DLNA简介.md
│ │ │ ├── 搭建nginx+rtmp服务器.md
│ │ │ ├── 视频播放相关内容总结.md
│ │ │ ├── 视频解码之软解与硬解.md
│ │ │ └── 音视频基础知识.md
│ │ ├── WebNote/
│ │ │ ├── MySQL相关/
│ │ │ │ ├── ERROR-1045-(28000)--Access-denied-for-user-'debian-sys-maint'@'localho.md
│ │ │ │ ├── Error--ER_TRUNCATED_WRONG_VALUE_FOR_FIELD.md
│ │ │ │ ├── Mysql导出数据库、表(有无数据).md
│ │ │ │ ├── mysql基础操作.md
│ │ │ │ └── 云服务器linux下安装MySQL.md
│ │ │ └── NodeJS相关/
│ │ │ ├── koa框架对post内容读取并解析.md
│ │ │ ├── nodejs查询数据库后将值返回前端.md
│ │ │ ├── nodejs项目在云服务器的部署.md
│ │ │ ├── test.html
│ │ │ └── 淘宝cnpm.md
│ │ ├── webRTC相关/
│ │ │ ├── WebRTC-Android源码解析.md
│ │ │ ├── WebRTC——Android入门.md
│ │ │ ├── WebRTC——AudioRenderer解析.md
│ │ │ ├── WebRTC——AudioSource、VideoSource解析.md
│ │ │ ├── WebRTC——AudioTrack-VideoTrack解析.md
│ │ │ ├── WebRTC——IceCandidate、SdpObserver、CameraSession解析.md
│ │ │ ├── WebRTC——MediaSource-java解析.md
│ │ │ ├── WebRTC——MeidaStreamTrack解析.md
│ │ │ ├── WebRTC——PeerConnection-java解析.md
│ │ │ ├── WebRTC——PeerConnectionFactory-java解析.md
│ │ │ ├── WebRTC——VideoFileRenderer解析.md
│ │ │ └── WebRTC——VideoRenderer解析.md
│ │ ├── 内存性能.md
│ │ └── 网络协议/
│ │ ├── SSH原理与应用.md
│ │ ├── 浅析Hessian协议.md
│ │ ├── 浅析RPC协议.md
│ │ ├── 浅析dubbo服务.md
│ │ └── 浅析socket.md
│ ├── interview/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── android/
│ │ │ ├── README.md
│ │ │ ├── SUMMARY.md
│ │ │ ├── activity-view-window.md
│ │ │ ├── arch.md
│ │ │ ├── binder.md
│ │ │ ├── broadcast.md
│ │ │ ├── canvas.md
│ │ │ ├── draw.md
│ │ │ ├── event.md
│ │ │ ├── eventbus.md
│ │ │ ├── handler.md
│ │ │ ├── intent.md
│ │ │ ├── keep-live.md
│ │ │ ├── launchmod.md
│ │ │ ├── lifecicle.md
│ │ │ ├── listview.md
│ │ │ ├── okhttp.md
│ │ │ ├── optimize.md
│ │ │ ├── push.md
│ │ │ ├── questions.md
│ │ │ └── version.md
│ │ ├── architecture/
│ │ │ ├── 1-cap.md
│ │ │ ├── README.md
│ │ │ ├── concurrent/
│ │ │ │ ├── 1-flow_control.md
│ │ │ │ └── README.md
│ │ │ ├── design/
│ │ │ │ ├── 1-tinyURL.md
│ │ │ │ └── README.md
│ │ │ └── distributed/
│ │ │ ├── 1-session.md
│ │ │ ├── 2-cache.md
│ │ │ ├── 3-lock.md
│ │ │ ├── 4-transaction.md
│ │ │ ├── 5-mq.md
│ │ │ ├── 6-zk.md
│ │ │ ├── 7-kafka.md
│ │ │ ├── 8-rpc.md
│ │ │ ├── 9-dubbo.md
│ │ │ └── README.md
│ │ ├── basic/
│ │ │ ├── README.md
│ │ │ ├── algo/
│ │ │ │ ├── README.md
│ │ │ │ ├── algo.md
│ │ │ │ ├── hash.md
│ │ │ │ ├── kmp.md
│ │ │ │ ├── mst.md
│ │ │ │ ├── path.md
│ │ │ │ ├── questions.md
│ │ │ │ ├── search.md
│ │ │ │ ├── skip_list.md
│ │ │ │ ├── sort.md
│ │ │ │ └── tree.md
│ │ │ ├── cryptology.md
│ │ │ ├── database/
│ │ │ │ ├── README.md
│ │ │ │ ├── concurrent_control.md
│ │ │ │ ├── index.md
│ │ │ │ ├── innodb.md
│ │ │ │ ├── join.md
│ │ │ │ ├── mysql.md
│ │ │ │ ├── questions.md
│ │ │ │ ├── redis.md
│ │ │ │ ├── sql.md
│ │ │ │ └── transaction.md
│ │ │ ├── net/
│ │ │ │ ├── README.md
│ │ │ │ ├── base_protocol.md
│ │ │ │ ├── http.md
│ │ │ │ ├── https.md
│ │ │ │ ├── ip.md
│ │ │ │ ├── osi.md
│ │ │ │ ├── questions.md
│ │ │ │ └── tcp.md
│ │ │ └── op/
│ │ │ ├── README.md
│ │ │ ├── arch.md
│ │ │ ├── concurrency.md
│ │ │ ├── device.md
│ │ │ ├── disk.md
│ │ │ ├── interrupt.md
│ │ │ ├── io.md
│ │ │ ├── linux.md
│ │ │ ├── memory.md
│ │ │ ├── os.md
│ │ │ └── questions.md
│ │ ├── fromwork/
│ │ │ ├── README.md
│ │ │ ├── mybatis/
│ │ │ │ ├── 1-question.md
│ │ │ │ ├── 2-cache.md
│ │ │ │ └── 3-proxy.md
│ │ │ └── spring/
│ │ │ ├── 1-ioc.md
│ │ │ ├── 2-design-partten.md
│ │ │ ├── 3-aop.md
│ │ │ └── README.md
│ │ └── java/
│ │ ├── 1-oop.md
│ │ ├── 17-questions.md
│ │ ├── 2-operator.md
│ │ ├── 3-exception.md
│ │ ├── 4-generics.md
│ │ ├── 5-object.md
│ │ ├── 6-StringBuilder.md
│ │ ├── 7-proxy.md
│ │ ├── README.md
│ │ ├── collection/
│ │ │ ├── 1-collection.md
│ │ │ ├── 2-HashMap.md
│ │ │ ├── 3-Concurrenthashmap.md
│ │ │ └── 4-BlockQueue.md
│ │ ├── concurrent/
│ │ │ ├── 1-thread.md
│ │ │ ├── 2-volatile.md
│ │ │ ├── 3-synchronized.md
│ │ │ ├── 4-AQS.md
│ │ │ ├── 5-threadlocal.md
│ │ │ ├── 6-interrupt.md
│ │ │ └── 7-CountDownLatch.md
│ │ ├── gc/
│ │ │ ├── 11-jvm-gc.md
│ │ │ └── 12-jvm-object-life-cycle.md
│ │ └── jvm/
│ │ ├── 1-jvm-class-load-init.md
│ │ ├── 2-jvm-class-loader.md
│ │ ├── 3-dispatcher.md
│ │ └── 4-jvm-architecture.md
│ ├── self.md
│ └── sources/
│ ├── JavaGarbageCollection.md
│ ├── JavaMemoryMode.md
│ ├── activity_onnewIntent.md
│ ├── adsl.md
│ ├── app_start_step.md
│ ├── application.md
│ ├── application_service.md
│ ├── asynctask.md
│ ├── binder.md
│ ├── butterknife.md
│ ├── davik_art.md
│ ├── design_v28.md
│ ├── eventbus.md
│ ├── fifo.md
│ ├── foreach.md
│ ├── fragment_lazy_load.md
│ ├── frame.md
│ ├── glide.md
│ ├── handle_leak.md
│ ├── hash_confict.md
│ ├── hotfix.md
│ ├── imagedownload.md
│ ├── iterationAndroidrecursion.md
│ ├── java8.md
│ ├── javaCopy.md
│ ├── javabasic.md
│ ├── javacollection.md
│ ├── killprocess_system_exit.md
│ ├── kotlin/
│ │ └── builderModel.kt
│ ├── livedata.md
│ ├── lru.md
│ ├── media_player.md
│ ├── netsafe.md
│ ├── okhttp.md
│ ├── onMeasure.md
│ ├── recyclerView_listview.md
│ ├── reference.md
│ ├── requestlayout_invalidate_postInvalidate.md
│ ├── retrofit.md
│ ├── rxjavademo.md
│ ├── seven_design_principles.md
│ ├── singleInstance.md
│ ├── synchronized_lock.md
│ ├── thread_principle.md
│ ├── tomcat_cache.java
│ ├── tomcat_lru_cache.java
│ ├── transactiontoolargeexception.md
│ ├── tree.md
│ ├── tu.md
│ ├── v4_v7_v8_v13.md
│ ├── view_root.md
│ ├── viewmodel.md
│ ├── volatile.md
│ ├── volley_algorithm.md
│ ├── wait_sleep.md
│ ├── weakHashMap.md
│ ├── workManager.md
│ └── yield_join.md
├── data/
│ └── java-recommended-books.md
├── dataStructures-algorithms/
│ ├── Backtracking-NQueens.md
│ ├── 公司真题.md
│ ├── 几道常见的子符串算法题.md
│ ├── 几道常见的链表算法题.md
│ ├── 剑指offer部分编程题.md
│ ├── 数据结构.md
│ └── 算法学习资源推荐.md
├── database/
│ ├── MySQL Index.md
│ ├── MySQL.md
│ ├── MySQL高性能优化规范建议.md
│ ├── Redis/
│ │ ├── Redis.md
│ │ ├── Redis持久化.md
│ │ ├── Redlock分布式锁.md
│ │ └── 如何做可靠的分布式锁,Redlock真的可行么.md
│ ├── 一千行MySQL命令.md
│ ├── 一条sql语句在mysql中如何执行的.md
│ └── 事务隔离级别(图文详解).md
├── essential-content-for-interview/
│ ├── BATJrealInterviewExperience/
│ │ └── 5面阿里,终获offer.md
│ ├── MostCommonJavaInterviewQuestions/
│ │ ├── 第一周(2018-8-7).md
│ │ ├── 第二周(2018-8-13).md
│ │ └── 第四周(2018-8-30).md
│ ├── PreparingForInterview/
│ │ ├── JavaInterviewLibrary.md
│ │ ├── JavaProgrammerNeedKnow.md
│ │ ├── interviewPrepare.md
│ │ ├── 如果面试官问你“你有什么问题问我吗?”时,你该如何回答.md
│ │ ├── 程序员的简历之道.md
│ │ └── 美团面试常见问题总结.md
│ ├── 手把手教你用Markdown写一份高质量的简历.md
│ ├── 简历模板.md
│ └── 面试必备之乐观锁与悲观锁.md
├── github-trending/
│ ├── 2018-12.md
│ ├── 2019-1.md
│ ├── 2019-2.md
│ ├── 2019-3.md
│ └── JavaGithubTrending.md
├── java/
│ ├── ArrayList-Grow.md
│ ├── ArrayList.md
│ ├── BIO-NIO-AIO.md
│ ├── Basis/
│ │ ├── Arrays,CollectionsCommonMethods.md
│ │ └── final、static、this、super.md
│ ├── HashMap.md
│ ├── J2EE基础知识.md
│ ├── Java IO与NIO.md
│ ├── Java基础知识.md
│ ├── Java编程规范.md
│ ├── Java虚拟机(jvm).md
│ ├── Java集合框架常见面试题总结.md
│ ├── LinkedList.md
│ ├── Multithread/
│ │ ├── AQS.md
│ │ ├── Atomic.md
│ │ ├── BATJ都爱问的多线程面试题.md
│ │ ├── ConcurrentProgramming1-并发编程基础知识.md
│ │ └── 并发容器总结.md
│ ├── What's New in JDK8/
│ │ ├── JDK8接口规范-静态、默认方法.md
│ │ ├── Java8Tutorial.md
│ │ ├── Java8教程推荐.md
│ │ ├── Lambda表达式.md
│ │ ├── README.md
│ │ ├── Stream.md
│ │ ├── 改进的类型推断.md
│ │ └── 通过反射获得方法的参数信息.md
│ ├── synchronized.md
│ ├── 可能是把Java内存区域讲的最清楚的一篇文章.md
│ ├── 多线程系列.md
│ ├── 搞定JVM垃圾回收就是这么简单.md
│ └── 这几道Java集合框架面试题几乎必问.md
├── network/
│ ├── HTTPS中的TLS.md
│ ├── 干货:计算机网络知识总结.md
│ └── 计算机网络.md
├── notes/
│ ├── Leetcode-Database 题解.md
│ ├── SQL.md
│ ├── 攻击技术.md
│ ├── 数据库系统原理.md
│ ├── 构建工具.md
│ ├── 正则表达式.md
│ ├── 计算机操作系统 - 内存管理.md
│ ├── 计算机操作系统 - 概述.md
│ ├── 计算机操作系统 - 死锁.md
│ ├── 计算机操作系统 - 目录.md
│ ├── 计算机操作系统 - 目录1.md
│ ├── 计算机操作系统 - 设备管理.md
│ ├── 计算机操作系统 - 进程管理.md
│ └── 计算机操作系统 - 链接.md
├── operating-system/
│ ├── Shell.md
│ └── 后端程序员必备的Linux基础知识.md
├── system-design/
│ ├── data-communication/
│ │ ├── dubbo.md
│ │ ├── message-queue.md
│ │ ├── rabbitmq.md
│ │ └── 数据通信(RESTful、RPC、消息队列).md
│ ├── framework/
│ │ ├── SpringBean.md
│ │ ├── SpringMVC 工作原理详解.md
│ │ ├── Spring学习与面试.md
│ │ ├── ZooKeeper.md
│ │ └── ZooKeeper数据模型和常见命令.md
│ ├── website-architecture/
│ │ ├── 8 张图读懂大型网站技术架构.md
│ │ ├── 【面试精选】关于大型网站系统架构你不得不懂的10个问题.md
│ │ └── 分布式.md
│ └── 设计模式.md
└── tools/
├── Docker-Image.md
├── Docker.md
└── Git.md
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 pengMaster
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<h1 align="center">Java Android学习/面试指南 </h1>
<!--| Ⅰ | Ⅱ | Ⅲ | Ⅳ | Ⅴ | Ⅵ | Ⅶ | Ⅷ | Ⅸ | Ⅹ | Ⅹ | Ⅹ |
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|:------:|
| Flutter[:iphone:](#Flutter)| Android[:pencil2:](#Android) | Java[:coffee:](#Java)|Kotlin[:unlock:](#Kotlin) | 面试[:memo:](#面试指南) |网络[:cloud:](#网络协议)| 操作系统 [:computer:](#操作系统)| 系统设计[:bulb:](#系统设计)| 工具[:wrench:](#工具)| 数据库[:floppy_disk:](#数据库)| 算法[:pencil2:](#数据结构与算法) | TODO学习清单[:page_facing_up:](#TODO学习清单) |-->
| Flutter| Android | Java | Kotlin | 面试 | 网络 | 系统 | 系统设计 | 工具 | 数据库 | 算法 |TODO |
| :--------:| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|:------:|
| [ :iphone:](#Flutter)| [:pencil2:](#Android) | [:coffee:](#Java)|[:unlock:](#Kotlin) | [:memo:](#面试指南) |[:cloud:](#网络)| [:computer:](#操作系统)| [:bulb:](#系统设计)| [:wrench:](#工具)| [:floppy_disk:](#数据库)| [:pencil2:](#数据结构与算法) | [:page_facing_up:](#TODO学习清单) |
<br>
## 目录
- [Android](#Android)
- [基础](#基础知识)
- [进阶](#进阶)
- [Gradle相关](#Gradle相关)
- [自定义View](#自定义View)
- [插件化相关](#插件化相关)
- [热修复相关](#热修复相关)
- [编译器相关](#编译器相关)
- [框架源码分析](#框架源码分析)
- [性能优化](#性能优化)
- [Android常见设计模式](#Android常见设计模式)
- [音视频开发](#音视频开发)
- [开源框架](#开源框架)
- [应用发布](#应用发布)
- [打包](#打包)
- [原生功能讲解](docs/android/AndroidNote/READMENote.md)
- [Java](#java)
- [基础](#基础)
- [容器](#容器)
- [并发](#并发)
- [JVM](#jvm)
- [I/O](#io)
- [Java 8](#java-8)
- [编程规范](#编程规范)
- [TODO学习清单](#TODO学习清单)
- [Kotlin学习](#Kotlin)
- [Flutter学习](#Flutter)
- [面试指南](#面试指南)
- [备战面试](#备战面试)
- [常见面试题总结](#常见面试题总结)
- [面经](#面经)
- [Android面试专场](docs/android/Android-Interview/README.md)
- [网络协议](#网络)
- [操作系统](#操作系统)
- [Linux相关](#linux相关)
- [计算机操作系统](#计算机操作系统)
- [数据结构与算法](#数据结构与算法)
- [数据结构](#数据结构)
- [算法](#算法)
- [数据库](#数据库)
- [MySQL](#mysql)
- [Redis](#redis)
- [数据库系统原理](docs/notes/数据库系统原理.md)
- [SQL](docs/notes/SQL.md)
- [Leetcode-Database 题解](docs/notes/Leetcode-Database%20题解.md)
- [系统设计](#系统设计)
- [设计模式](#设计模式)
- [常用框架](#常用框架)
- [数据通信](#数据通信)
- [网站架构](#网站架构)
- [攻击技术](docs/notes/攻击技术.md)
- [工具](#工具)
- [Git](#git)
- [Docker](#Docker)
- [构建工具](docs/notes/构建工具.md)
- [正则表达式](docs/notes/正则表达式.md)
- [常见问题](docs/android/interview/README.md)
## Android
### 基础知识
* [Activity详细解析](docs/android/AndroidNote/Android基础/Activity详细解析.md)
* [Service详细解析](docs/android/AndroidNote/Android基础/Service详细解析.md)
* [IntentService详细解析](docs/android/AndroidNote/Android基础/IntentService详细解析.md)
* [IntentService原理解析文章](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=401611665&idx=1&sn=9b6b1f2924d4adfe4e89a322ab53df9c&scene=21#wechat_redirect)
* [ContentProvider实例详解](docs/android/AndroidNote/Android基础/ContentProvider实例详解.md)
* [BroadcastReceiver详细解析](docs/android/AndroidNote/Android基础/BroadcastReceiver详细解析.md)
* [Android异步任务机制之AsycTask](docs/android/AndroidNote/Android基础/Android异步任务机制之AsycTask.md)
* [Handler,Looper,MessageQueue关系](docs/android/AndroidNote/Android基础/Handler,Looper,MessageQueue关系.md)
* [Android-SQLite的基本使用](docs/android/AndroidNote/Android基础/Android-SQLite的基本使用.md)
* [Android系统相机与相册的使用](docs/android/AndroidNote/Android基础/Android中相机与相册的详细使用.md)
* [图片缓存原理](docs/android/AndroidNote/Android基础/图片缓存原理.md)
* [Android数据存储的五种方式](docs/android/AndroidNote/Android基础/Android数据存储的五种方式.md)
* [Android跟随手指移动的View](docs/android/AndroidNote/Android基础/Android跟随手指移动的view.md)
* [RecyclerView的使用](docs/android/AndroidNote/Android基础/RecyclerView的简介.md)
* [Android获取SHA1](docs/android/AndroidNote/Android基础/Android获取SHA1.md)
* [Recyclerview和Listview的异同.md](docs/android/AndroidNote/Android进阶/Recyclerview和Listview的异同.md)
* [初识ConstraintLayout](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548068&idx=1&sn=f750ae79c9458f89c3cf85f7573ba579&scene=21#wechat_redirect)
* [TabLayout记录](docs/android/AndroidNote/Android基础/tablayout记录.md)
* [用SpannableString打造绚丽多彩的文本显示效果](http://www.jianshu.com/p/84067ad289d2)
* [解析ConstraintLayout的性能优势](https://mp.weixin.qq.com/s/gGR2itbY7hh9fo61SxaMQQ)
* [Android新特性介绍,ConstraintLayout完全解析](https://blog.csdn.net/guolin_blog/article/details/53122387)
* [Android新特性介绍,ConstraintLayout完全解析](https://blog.csdn.net/guolin_blog/article/details/53122387)
* [Android 一个无限循环滚动的卡片式ViewPager](https://blog.csdn.net/qq_30552993/article/details/76208535)
* [Android 中获取控件宽和高的方法(详细解析)](https://blog.csdn.net/CodeIsPoisonous/article/details/54316025)
### 进阶
* [Android 学习笔记核心篇](https://juejin.im/post/5c46db4ae51d4503834d8227)
* [Android内存泄漏性能优化总结](docs/android/AndroidNote/内存性能.md)
* [进程间通信详解](docs/android/AndroidNote/IPC.md)
* [Android中的动画](docs/android/AndroidNote/Android进阶/Android中的动画.md)
* [深入了解MVXX模式](docs/android/AndroidNote/Android进阶/深入了解MVXX模式.md)
* [Android项目总结](docs/android/AndroidNote/Android进阶/Android项目总结.md)
* [Android项目总结2](docs/android/AndroidNote/Android进阶/Android项目总结2.md)
* [自定义RadioGroup](docs/android/AndroidNote/Android进阶/自定义RadioGroup.md)
* [Android导入项目一直在Building的解决方案](docs/android/AndroidNote/Android进阶/AndroidStudio导入工程一直在Building的解决方案.md)
* [基于TOTP的双向认证算法](docs/android/AndroidNote/Android进阶/基于OTP算法的双向认证.md)
* [基于TOTP的双向认证算法](docs/android/AndroidNote/Android进阶/基于OTP算法的双向认证.md)
* [Android 触控事件解析 - Mastering The Android Touch System 笔记](https://www.jianshu.com/p/c65da5e81afd)
* [《Android 高性能编程》—— @IntDef 注解,减缓枚举的使用](https://blog.csdn.net/OneDeveloper/article/details/79973205)
* [Android官网建议代码规范](https://source.android.com/source/code-style#java-language-rules)
* [30多年编码经验总结成10条最佳实践](https://mp.weixin.qq.com/s?__biz=MzIyMjQ0MTU0NA==&mid=2247484524&idx=1&sn=5b2759e6d89f01e61d021545ca7556b9&chksm=e82c3d4bdf5bb45dd77227982931ede8229ee6910829253a57bb905e810c89bd3f0a162786e8&mpshare=1&scene=23&srcid=1023FjKcLWtRlcDpwEeeJnCN#rd)
* [Android中利用异步来优化处理速度](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=401555104&idx=1&sn=501e6158e6eb26b4e86467be01fd290e&scene=21#wechat_redirect)
* [三大图片缓存框架的对比](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649547344&idx=2&sn=e3fa99b52055a37202634fe61a62d439&scene=21#wechat_redirect)
* [SVG图片在Android中的应用](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548366&idx=1&sn=6cbdf8652ec139859d9be01444e1ad3b&chksm=f1180d33c66f8425a286de4fd5f03aa89308add3593529a91356439cb8c2f8542305561034c8&scene=21#wechat_redirect)
* [携程App的网络性能优化实践](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649547359&idx=1&sn=9f069a28f5dbe73fb6c241cfa1049571&scene=21#wechat_redirect)
* [途牛插件化原理](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649547401&idx=1&sn=e615735d600f987a7f769f7e278d0840&scene=21#wechat_redirect)
* [Android分包原理](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649547390&idx=1&sn=1fae14b1753e437a032640be81c475b8&scene=21#wechat_redirect)
* [插件化实现的思想](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649547660&idx=1&sn=d2764b282fdf1c1fdb629f9c2ca9b10f&scene=21#wechat_redirect)
* [Android 7.0新特性总结](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649548427&idx=1&sn=df9956d131a6da5f29292cd05a61b16e&chksm=f1180df6c66f84e0097eea33bba6abb125b6bcd6847720a7c481a85001a52ae2e4b1941690eb&scene=21#wechat_redirect)
* [RecyclerView局部刷新的坑](http://blog.csdn.net/jdsjlzx/article/details/52893469)
* [Android单元测试](https://tech.meituan.com/Android_unit_test.html)
* [gradle 详解——你真的了解Gradle吗?](http://blog.csdn.net/u013132758/article/details/52355915)
* [AndroidStudio-Gradle多渠道打包](http://stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/)
* [Android基础入门教程——8.1.1 Android中的13种Drawable小结 Part 1](http://blog.csdn.net/coder_pig/article/details/49006217)
* [Android基础入门教程——8.1.2 Android中的13种Drawable小结 Part 2](http://blog.csdn.net/coder_pig/article/details/49008397)
* [Android-Drawable高级用法](http://blog.csdn.net/lmj623565791/article/details/43752383)
* [安卓开踩过的坑:你的 Bitmap 究竟占多大内存?](http://dev.qq.com/topic/591d61f56793d26660901b4e)
* [Android 4.4 中 WebView 使用注意事项](https://github.com/cundong/blog/blob/master/Android%204.4%20%E4%B8%AD%20WebView%20%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9.md)
* [Android图像处理 - 高斯模糊的原理及实现](https://mp.weixin.qq.com/s?__biz=MzI2MTU3MTE4NQ==&mid=2247483896&idx=1&sn=50c61e2c78aa610a1944be6a89bd75e5&chksm=ea5916e6dd2e9ff0a62af64c7f345ffb5c6dafdb65847b757b99afcc6fed8e1270e915dbcb25&mpshare=1&scene=23&srcid=1001DxwdQpiMwea74mczpSw8#rd)
* [Android实战——GreenDao3.2的使用,爱不释手](https://mp.weixin.qq.com/s/4Nx2DacsK65O5LanPZUszA)
* [Realm for Android详细教程](http://www.jianshu.com/p/28912c2f31db#)
* [给 Android 开发者的 RxJava 详解](http://gank.io/post/560e15be2dca930e00da1083)
* [Android 谈谈自动化测试](https://mp.weixin.qq.com/s/-0e1wd2iveQPMWgGFcmOwQ)
* [检查app是否具有通知栏权限](docs/android/AndroidNote/Android进阶/检查app是否有推送权限.md)
* [Android中图片压缩分析(上)](https://mp.weixin.qq.com/s/QZ-XTsO7WnNvpnbr3DWQmg)
* [Android Studio3.0更新之路(遇坑必入)](http://www.jianshu.com/p/15afb8234d19)
* [Android Studio3.0正式版填坑路](http://www.jianshu.com/p/9b25087a5d7d)
* [Android混合编程:WebView实践](https://juejin.im/post/59f17a7051882546d71e91a7)
* [runOnUiThread 、Handler.post、View.post之间的区别](https://blog.csdn.net/dengpeng_/article/details/78804404)
* [理解 Activity.runOnUiThread](https://www.jianshu.com/p/e39449026f21)
* [说说 getMainLooper](http://www.icodeyou.com/2015/10/11/2015-10-11-getMainLooper/)
* [Android 探究 LayoutInflater setFactory](https://blog.csdn.net/lmj623565791/article/details/51503977)
* [巧用ViewPager 打造不一样的广告轮播切换效果](https://blog.csdn.net/lmj623565791/article/details/51339751)
* [为RecyclerView打造通用Adapter 让RecyclerView更加好用](https://blog.csdn.net/lmj623565791/article/details/51118836)
* [MNCrashMonitor 监听程序崩溃日志,直接页面展示崩溃日志列表](http://www.wanandroid.com/blog/show/2207)
* [『进阶之路』—— 线程池](http://www.wanandroid.com/blog/show/2264)
* [从json文件到炫酷动画-Lottie实现思路和源码分析](https://www.jianshu.com/p/81be1bf9600c)
* [Lottie动画库 Android 端源码浅析](http://chenhaohui.com/2017/03/13/sd/)
### Gradle相关
* [如何理解 Transform API](https://juejin.im/entry/59776f2bf265da6c4741db2b)
* [Gradle自定义插件详解](https://www.jianshu.com/p/03eb55536298)
* [Android 突破 DEX 文件的 64k方法数限制](http://yifeng.studio/2016/10/26/android-64k-methods-count/)
* [Android Dex分包之旅](http://yydcdut.com/2016/03/20/split-dex/)
* [美团Android DEX自动拆包及动态加载简介](https://tech.meituan.com/mt-android-auto-split-dex.html)
* [gradle简单入门系列](http://www.cnblogs.com/davenkin/p/gradle-learning-1.html)
* [Gradle简单配置](https://mp.weixin.qq.com/s/1UHcYOudViMhpUYeREZzGA)
* [Android 如何编写基于编译时注解的项目](https://blog.csdn.net/lmj623565791/article/details/51931859)
* [Gradle 完整指南(Android)](https://www.jianshu.com/p/9df3c3b6067a)
* [NDK-JNI开发入门教程项目](https://github.com/pengMaster/NDKJniDemo)
* [深入理解Android之Gradle Groovy](https://blog.csdn.net/innost/article/details/48228651)
* [Groovy 闭包](https://www.jianshu.com/p/6dc2074480b8)
* [要点提炼| Gradle指南](https://www.jianshu.com/p/1274c1f1b6a4)
* [Gradle专题][39]
* [发布library到Maven仓库][40]
### 自定义View
* [自定义View入门](docs/android/AndroidNote/Android自定义View/自定义View入门.md)
* [自定义view详细教程](https://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649547668&idx=1&sn=b2667c46188c6674c90aa72c2fba4719&scene=21#wechat_redirect)
* [自定义ViewGroup入门](docs/android/AndroidNote/Android自定义View/自定义ViewGroup入门.md)
* [Android事件分发机制](docs/android/AndroidNote/Android自定义View/Android事件分发机制.md)
* [CameraView](docs/android/AndroidNote/Android自定义View/自定义View——CameraView.md)
* [CheckView](docs/android/AndroidNote/Android自定义View/自定义View——CheckView.md)
* [CircleView](docs/android/AndroidNote/Android自定义View/自定义View——CircleView.md)
* [FlowLayout](docs/android/AndroidNote/Android自定义View/自定义View——FlowLayout.md)
* [PieView](docs/android/AndroidNote/Android自定义View/自定义View——PieView.md)
* [SlideslipListView](docs/android/AndroidNote/Android自定义View/自定义view——sideslipListView.md)
* [二阶贝塞尔曲线](docs/android/AndroidNote/Android自定义View/二阶贝塞尔曲线.md)
* [三阶贝塞尔曲线](docs/android/AndroidNote/Android自定义View/三阶贝塞尔曲线.md)
* [贝塞尔曲线Demo](https://github.com/linsir6/mCustomView/tree/master/BezierDemo)
* [具有弹性的小球](https://github.com/linsir6/mCustomView/tree/master/MagicCircle)
* [PathMeasure](docs/android/AndroidNote/Android自定义View/PathMeasure.md)
## Android常见设计模式
* **Android常见设计模式**
* [观察者模式](https://blog.csdn.net/chengyuqiang/article/details/79222294)
* [策略模式](https://github.com/pengMaster/strategyMode)
* [建造者模式](https://www.jianshu.com/p/154948d5adc6)
* [适配器模式](https://blog.csdn.net/u012583459/article/details/47079529)
* [代理模式](https://blog.csdn.net/u012583459/article/details/47079529)
* [工厂模式](https://blog.csdn.net/u012583459/article/details/47079549)
* [单例模式](https://blog.csdn.net/u012583459/article/details/47079549)
* [命令模式](https://blog.csdn.net/u012583459/article/details/47079549)
### 音视频开发
- [音视频开发][44]
- [搭建nginx+rtmp服务器][18]
- [视频播放相关内容总结][19]
- [视频解码之软解与硬解][20]
- [音视频基础知识][21]
- [Android WebRTC简介][22]
- [Android音视频开发知识(未完)][23]
- [DLNA简介][24]
### 热修复相关
* [Android 热修复 Tinker Gradle Plugin解析](https://blog.csdn.net/lmj623565791/article/details/72667669)
* [Android 热修复 Tinker接入及源码浅析](https://blog.csdn.net/lmj623565791/article/details/54882693)
* [Android 热修复 Tinker 源码分析之DexDiff / DexPatch](https://blog.csdn.net/lmj623565791/article/details/60874334)
### 插件化相关
* [滴滴插件化方案 VirtualApk 源码解析](https://blog.csdn.net/lmj623565791/article/details/75000580)
### 编译器相关
* [Android Studio 3.0 新功能解析和旧项目适配](https://mp.weixin.qq.com/s/met0fke7rKumb7Nlb5hxpA)
* [Android-studio使用教程1](docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第一弹).md)
* [Android-studio使用教程2](docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第二弹).md)
* [Android-studio使用教程3](docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第三弹).md)
* [Android-studio使用教程4](docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第四弹).md)
* [Android-studio使用教程5](docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第五弹).md)
* [Android-studio使用教程6](docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第六弹).md)
* [Android-studio使用教程7](docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第七弹).md)
### 性能优化
* [Android开发性能优化总结(一)](http://blog.csdn.net/gs12software/article/details/51173392)
* [Android开发性能优化总结(二)](http://blog.csdn.net/gs12software/article/details/51234454)
### 开源框架
* [当下流行开源框架总览](docs/android/AndroidNote/Android开源框架相关/Android当下最流行的开源框架总结.md)
* [easypermission](docs/android/AndroidNote/Android开源框架相关/动态申请权限库:easypermissions使用与源码解析.md)
* [ButterKnifeZelezny](docs/android/AndroidNote/Android开源框架相关/Android黑科技——ButterKnifeZelezny.md)
* [RxJava+retrofit2](docs/android/AndroidNote/Android开源框架相关/RxJava+retrofit2实现安卓中网络操作.md)
* [LinLog](docs/android/AndroidNote/Android开源框架相关/一款Android的Log、Toast的库.md)
* [Retrofit 2.0 使用教程](http://www.jianshu.com/p/a3e162261ab6)
* [retrofit 2.0 源码解析](http://www.jianshu.com/p/0c055ad46b6c)
* [关于 RxJava 背压](https://juejin.im/entry/58e704cbac502e4957b230eb)
* [RxJava 2.0中backpressure(背压)概念的理解](https://blog.csdn.net/jdsjlzx/article/details/52717636)
* [Retrofit2 完全解析 探索与okhttp之间的关系](https://blog.csdn.net/lmj623565791/article/details/51304204)
*[Dagger2][199]
- [1.Dagger2简介(一).md][200]
- [2.Dagger2入门demo(二).md][201]
- [3.Dagger2入门demo扩展(三).md][202]
- [4.Dagger2单例(四).md][203]
- [5.Dagger2Lay和Provider(五).md][204]
- [6.Dagger2Android示例代码(六).md][205]
- [7.Dagger2之dagger-android(七).md][206]
- [8.Dagger2与MVP(八).md][207]
- [9.Dagger2原理分析(九).md][212]
* [图片加载][45]
- [Glide简介(上)][25]
- [Glide简介(下)][26]
- [图片加载库比较][27]
* [RxJava][46]
- [RxJava详解(一)][28]
- [RxJava详解(二)][29]
- [RxJava详解(三)][30]
- [RxJava详解之执行原理(四)][209]
- [RxJava详解之操作符执行原理(五)][210]
- [RxJava详解之线程调度原理(六)][211]
- [RxJava系列全家桶][31]
### 应用发布
- [应用发布][50]
- [使用Jenkins实现自动化打包][198]
- [Android应用发布][41]
- [Zipalign优化][42]
### 打包
* [打包jar包或aar包](docs/android/AndroidNote/Android打包相关/Android将library打包成jar文件或aar文件.md)
* [发布sdk到jcenter](docs/android/AndroidNote/Android打包相关/Android发布sdk到jcenter.md)
##### 框架源码分析
- [EventBus源码分析](docs/android/sources/eventbus.md)
- [Bufferknife源码分析](docs/android/sources/butterknife.md)
- [Glide 源码分析](docs/android/sources/glide.md)
- [OKHttp 源码分析](docs/android/sources/okhttp.md)
- [Retrofit 源码分析](docs/android/sources/retrofit.md)
- [ViewModel 源码分析](docs/android/sources/viewmodel.md)
- [自定义View详解][1]
- [Activity界面绘制过程详解][2]
- [Activity启动过程][3]
- [Android Touch事件分发详解][4]
- [AsyncTask详解][5]
- [butterknife源码详解][6]
- [InstantRun详解][7]
- [ListView源码分析][8]
- [VideoView源码分析][9]
- [View绘制过程详解][10]
- [网络部分][11]
- [HttpURLConnection详解][12]
- [HttpURLConnection与HttpClient][13]
- [volley-retrofit-okhttp之我们该如何选择网路框架][14]
- [Volley源码分析][15]
- [Retrofit详解(上)][16]
- [Retrofit详解(下)][17]
## Kotlin
- [Kotlin学习][48]
- [Kotlin学习教程(一)][180]
- [Kotlin学习教程(二)][181]
- [Kotlin学习教程(三)][182]
- [Kotlin学习教程(四)][183]
- [Kotlin学习教程(五)][184]
- [Kotlin学习教程(六)][185]
- [Kotlin学习教程(七)][186]
- [Kotlin学习教程(八)][187]
- [Kotlin学习教程(九)][188]
- [Kotlin学习教程(十)][197]
- [集合之常用操作符汇总](https://www.cnblogs.com/Jetictors/p/9241867.html)
## Flutter
* **Flutter学习:**
* [flutter脚手架封装](https://github.com/pengMaster/flutter_app)
* [flutter中文学习网](https://book.flutterchina.club/chapter2/)
* [flutter常用库总结](https://www.cnblogs.com/yangyxd/p/9232308.html)
* [flutter开源项目](https://flutterchina.club/opensource.html)
* [flutter基础语法](https://www.jianshu.com/p/3d927a7bf020)
* [Flutter常用工具类](https://juejin.im/post/5d0f4c54f265da1bb31c426c?utm_source=gold_browser_extension)
* [Flutter-learning](https://github.com/AweiLoveAndroid/Flutter-learning)
* [Flutter-UI框架](https://bruno.ke.com/)
## TODO学习清单
- [TODO学习清单](docs/android/self.md)
## Java
### 基础
* [Java 基础知识回顾](docs/java/Java基础知识.md)
* [J2EE 基础知识回顾](docs/java/J2EE基础知识.md)
* [Collections 工具类和 Arrays 工具类常见方法](docs/java/Basis/Arrays%2CCollectionsCommonMethods.md)
* [Java常见关键字总结:static、final、this、super](docs/java/Basis/final、static、this、super.md)
* [Java常见关键字总结:static、final、this、super](docs/java/Basis/final、static、this、super.md)
### 容器
* **常见问题总结:**
* [这几道Java集合框架面试题几乎必问](docs/java/这几道Java集合框架面试题几乎必问.md)
* [Java 集合框架常见面试题总结](docs/java/Java集合框架常见面试题总结.md)
* **源码分析:**
* [ArrayList 源码学习](docs/java/ArrayList.md)
* [【面试必备】透过源码角度一步一步带你分析 ArrayList 扩容机制](docs/java/ArrayList-Grow.md)
* [LinkedList 源码学习](docs/java/LinkedList.md)
* [HashMap(JDK1.8)源码学习](docs/java/HashMap.md)
### 并发
* [并发编程面试必备:synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比](docs/java/synchronized.md)
* [并发编程面试必备:乐观锁与悲观锁](docs/essential-content-for-interview/面试必备之乐观锁与悲观锁.md)
* [并发编程面试必备:JUC 中的 Atomic 原子类总结](docs/java/Multithread/Atomic.md)
* [并发编程面试必备:AQS 原理以及 AQS 同步组件总结](docs/java/Multithread/AQS.md)
* [BATJ都爱问的多线程面试题](docs/java/Multithread/BATJ都爱问的多线程面试题.md)
* [并发容器总结](docs/java/Multithread/并发容器总结.md)
### JVM
* [可能是把Java内存区域讲的最清楚的一篇文章](docs/java/可能是把Java内存区域讲的最清楚的一篇文章.md)
* [搞定JVM垃圾回收就是这么简单](docs/java/搞定JVM垃圾回收就是这么简单.md)
* [《深入理解Java虚拟机》第2版学习笔记](docs/java/Java虚拟机(jvm).md)
### I/O
* [BIO,NIO,AIO 总结 ](docs/java/BIO-NIO-AIO.md)
* [Java IO 与 NIO系列文章](docs/java/Java%20IO与NIO.md)
### Java 8
* [Java 8 新特性总结](docs/java/What's%20New%20in%20JDK8/Java8Tutorial.md)
* [Java 8 学习资源推荐](docs/java/What's%20New%20in%20JDK8/Java8教程推荐.md)
### 编程规范
- [Java 编程规范](docs/java/Java编程规范.md)
## 网络
* [浅析socket](docs/android/AndroidNote/网络协议/浅析socket.md)
* [浅析Hessian](docs/android/AndroidNote/网络协议/浅析Hessian协议.md)
* [浅析RPC协议](docs/android/AndroidNote/网络协议/浅析RPC协议.md)
* [浅析dubbo服务](docs/android/AndroidNote/网络协议/浅析dubbo服务.md)
* [SSH原理与应用](docs/android/AndroidNote/网络协议/SSH原理与应用.md)
* [理解OAuth 2.0](http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html)
* [OAuth 2和JWT - 如何设计安全的API?](http://blog.csdn.net/ljinddlj/article/details/53108261)
* [计算机网络常见面试题](docs/network/计算机网络.md)
* [计算机网络基础知识总结](docs/network/干货:计算机网络知识总结.md)
* [HTTPS中的TLS](docs/network/HTTPS中的TLS.md)
## 操作系统
### Linux相关
* [后端程序员必备的 Linux 基础知识](docs/operating-system/后端程序员必备的Linux基础知识.md)
* [Shell 编程入门](docs/operating-system/Shell.md)
### 计算机操作系统
- [计算机操作系统](docs/notes/计算机操作系统%20-%20目录.md)
## 数据结构与算法
### 数据结构
- [数据结构知识学习与面试](docs/dataStructures-algorithms/数据结构.md)
### 算法
- [算法学习资源推荐](docs/dataStructures-algorithms/算法学习资源推荐.md)
- [算法总结——几道常见的子符串算法题 ](docs/dataStructures-algorithms/几道常见的子符串算法题.md)
- [算法总结——几道常见的链表算法题 ](docs/dataStructures-algorithms/几道常见的链表算法题.md)
- [剑指offer部分编程题](docs/dataStructures-algorithms/剑指offer部分编程题.md)
- [公司真题](docs/dataStructures-algorithms/公司真题.md)
- [回溯算法经典案例之N皇后问题](docs/dataStructures-algorithms/Backtracking-NQueens.md)
- [算法设计常用思想](docs/dataStructures-algorithms/Backtracking-NQueens.md)
## 数据库
### MySQL
* [MySQL 学习与面试](docs/database/MySQL.md)
* [一千行MySQL学习笔记](docs/database/一千行MySQL命令.md)
* [MySQL高性能优化规范建议](docs/database/MySQL高性能优化规范建议.md)
* [搞定数据库索引就是这么简单](docs/database/MySQL%20Index.md)
* [事务隔离级别(图文详解)](docs/database/事务隔离级别(图文详解).md)
* [一条SQL语句在MySQL中如何执行的](docs/database/一条sql语句在mysql中如何执行的.md)
* [linux下安装MySQL](docs/android/AndroidNote/WebNote/MySQL相关/云服务器linux下安装MySQL.md)
* [MySQL基础操作](docs/android/AndroidNote/WebNote/MySQL相关/mysql基础操作.md)
* [MySQL导出数据库、表](docs/android/AndroidNote/WebNote/MySQL相关/Mysql导出数据库、表(有无数据).md)
* [Error-ER_TRUNCATED_WRONG_VALUE_FOR_FIELD](docs/android/AndroidNote/WebNote/MySQL相关/Error--ER_TRUNCATED_WRONG_VALUE_FOR_FIELD.md)
* [ERROR-1045-(28000)--Access-denied-for-user-'debian-sys-maint'@'localhost](docs/android/AndroidNote/WebNote/MySQL相关/ERROR-1045-(28000)--Access-denied-for-user-'debian-sys-maint'@'localho.md)
* [mysql设置远程链接权限](https://www.cnblogs.com/gdsblog/p/7349551.html)
* [关于初次安装mysql8.01遇到的问题解决](https://blog.csdn.net/l569746927/article/details/80025364)
### Redis
* [Redis 总结](docs/database/Redis/Redis.md)
* [Redlock分布式锁](docs/database/Redis/Redlock分布式锁.md)
* [如何做可靠的分布式锁,Redlock真的可行么](docs/database/Redis/如何做可靠的分布式锁,Redlock真的可行么.md)
### 数据库系统原理
- [数据库系统原理](docs/notes/数据库系统原理.md)
### SQL
- [SQL](docs/notes/SQL.md)
### Leetcode-Database 题解
- [Leetcode-Database 题解](docs/notes/Leetcode-Database%20题解.md)
## 系统设计
### 设计模式
- [设计模式系列文章](docs/system-design/设计模式.md)
### 常用框架
#### Spring
- [Spring 学习与面试](docs/system-design/framework/Spring学习与面试.md)
- [Spring中bean的作用域与生命周期](docs/system-design/framework/SpringBean.md)
- [SpringMVC 工作原理详解](docs/system-design/framework/SpringMVC%20%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3.md)
#### ZooKeeper
- [可能是把 ZooKeeper 概念讲的最清楚的一篇文章](docs/system-design/framework/ZooKeeper.md)
- [ZooKeeper 数据模型和常见命令了解一下,速度收藏!](docs/system-design/framework/ZooKeeper数据模型和常见命令.md)
### 数据通信
- [数据通信(RESTful、RPC、消息队列)相关知识点总结](docs/system-design/data-communication/数据通信(RESTful、RPC、消息队列).md)
- [Dubbo 总结:关于 Dubbo 的重要知识点](docs/system-design/data-communication/dubbo.md)
- [消息队列总结:新手也能看懂,消息队列其实很简单](docs/system-design/data-communication/message-queue.md)
- [一文搞懂 RabbitMQ 的重要概念以及安装](docs/system-design/data-communication/rabbitmq.md)
### 网站架构
- [一文读懂分布式应该学什么](docs/system-design/website-architecture/分布式.md)
- [8 张图读懂大型网站技术架构](docs/system-design/website-architecture/8%20张图读懂大型网站技术架构.md)
- [【面试精选】关于大型网站系统架构你不得不懂的10个问题](docs/system-design/website-architecture/【面试精选】关于大型网站系统架构你不得不懂的10个问题.md)
### 攻击技术
- [攻击技术](docs/notes/攻击技术.md)
## 面试指南
### 备战面试
* [【备战面试1】程序员的简历就该这样写](docs/essential-content-for-interview/PreparingForInterview/程序员的简历之道.md)
* [【备战面试2】初出茅庐的程序员该如何准备面试?](docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md)
* [【备战面试3】7个大部分程序员在面试前很关心的问题](docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md)
* [【备战面试4】Github上开源的Java面试/学习相关的仓库推荐](docs/essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md)
* [【备战面试5】如果面试官问你“你有什么问题问我吗?”时,你该如何回答](docs/essential-content-for-interview/PreparingForInterview/如果面试官问你“你有什么问题问我吗?”时,你该如何回答.md)
* [【备战面试6】美团面试常见问题总结(附详解答案)](docs/essential-content-for-interview/PreparingForInterview/美团面试常见问题总结.md)
### 常见面试题总结
* [第一周(2018-8-7)](docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/第一周(2018-8-7).md) (为什么 Java 中只有值传递、==与equals、 hashCode与equals)
* [第二周(2018-8-13)](docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/第二周(2018-8-13).md)(String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?、什么是反射机制?反射机制的应用场景有哪些?......)
* [第三周(2018-08-22)](docs/java/这几道Java集合框架面试题几乎必问.md) (Arraylist 与 LinkedList 异同、ArrayList 与 Vector 区别、HashMap的底层实现、HashMap 和 Hashtable 的区别、HashMap 的长度为什么是2的幂次方、HashSet 和 HashMap 区别、ConcurrentHashMap 和 Hashtable 的区别、ConcurrentHashMap线程安全的具体实现方式/底层具体实现、集合框架底层数据结构总结)
* [第四周(2018-8-30).md](docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/第四周(2018-8-30).md) (主要内容是几道面试常问的多线程基础题。)
### 面经
- [5面阿里,终获offer(2018年秋招)](docs/essential-content-for-interview/BATJrealInterviewExperience/5面阿里,终获offer.md)
### Android面试专场
- [Android面试专场](docs/android/Android-Interview/README.md)
## 工具
### Git
* [Git入门](docs/tools/Git.md)
### Docker
* [Docker 入门](docs/tools/Docker.md)
* [一文搞懂 Docker 镜像的常用操作!](docs/tools/Docker-Image.md)
### 构建工具
* [构建工具](docs/notes/构建工具.md)
### 正则表达式
* [正则表达式](docs/notes/正则表达式.md)
## 致谢
本文并非原创,通过各位博主综合而得,以便供自己方便学习,在此感谢各位前辈,并在下面注明出处
- [Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
- [UCodeUStory/DataStructure](https://github.com/UCodeUStory/DataStructure)
- [JackChan1999/Android-Interview](https://github.com/JackChan1999/Android-Interview)
- [linsir6/AndroidNote](https://github.com/linsir6/AndroidNote)
- [CharonChui/AndroidNote](https://github.com/CharonChui/AndroidNote)
- [CS-Notes](https://github.com/CyC2018/CS-Notes)
<a href="https://github.com/Snailclimb/JavaGuide" >
<img src="https://avatars0.githubusercontent.com/u/29880145?s=400&v=4" width="50px">
</a>
<a href="https://github.com/UCodeUStory/DataStructure">
<img src="https://avatars3.githubusercontent.com/u/17451281?s=400&v=4" width="50px">
</a>
<a href="https://github.com/JackChan1999/Android-Interview">
<img src="https://avatars0.githubusercontent.com/u/16631168?s=400&v=4" width="50px">
</a>
<a href="https://github.com/linsir6/AndroidNote">
<img src="https://avatars2.githubusercontent.com/u/16979367?s=400&v=4" width="50px">
</a>
<a href="https://github.com/CharonChui/AndroidNote">
<img src="https://avatars0.githubusercontent.com/u/6140231?s=400&v=4" width="50px">
</a>
<a href="https://github.com/CyC2018/CS-Notes">
<img src="https://avatars0.githubusercontent.com/u/36260787?s=400&v=4" width="50px">
</a>
License
===
MIT License
Copyright (c) 2019 pengMaster
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
[1]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/%E8%87%AA%E5%AE%9A%E4%B9%89View%E8%AF%A6%E8%A7%A3.md "自定义View详解"
[2]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Activity%E7%95%8C%E9%9D%A2%E7%BB%98%E5%88%B6%E8%BF%87%E7%A8%8B%E8%AF%A6%E8%A7%A3.md "Activity界面绘制过程详解"
[3]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Activity%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B.md "Activity启动过程"
[4]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Android%20Touch%E4%BA%8B%E4%BB%B6%E5%88%86%E5%8F%91%E8%AF%A6%E8%A7%A3.md "Android Touch事件分发详解"
[5]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/AsyncTask%E8%AF%A6%E8%A7%A3.md "AsyncTask详解"
[6]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/butterknife%E6%BA%90%E7%A0%81%E8%AF%A6%E8%A7%A3.md "butterknife源码详解"
[7]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/InstantRun%E8%AF%A6%E8%A7%A3.md "InstantRun详解"
[8]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/ListView源码分析.md "ListView源码分析"
[9]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/VideoView%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.md "VideoView源码分析"
[10]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/View%E7%BB%98%E5%88%B6%E8%BF%87%E7%A8%8B%E8%AF%A6%E8%A7%A3.md "View绘制过程详解"
[11]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//SourceAnalysis/Netowork "网络部分"
[12]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Netowork/HttpURLConnection%E8%AF%A6%E8%A7%A3.md "HttpURLConnection详解"
[13]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Netowork/HttpURLConnection%E4%B8%8EHttpClient.md "HttpURLConnection与HttpClient"
[14]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Netowork/volley-retrofit-okhttp%E4%B9%8B%E6%88%91%E4%BB%AC%E8%AF%A5%E5%A6%82%E4%BD%95%E9%80%89%E6%8B%A9%E7%BD%91%E8%B7%AF%E6%A1%86%E6%9E%B6.md "volley-retrofit-okhttp之我们该如何选择网路框架"
[15]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Netowork/Volley%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.md "Volley源码分析"
[16]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Netowork/Retrofit%E8%AF%A6%E8%A7%A3(%E4%B8%8A).md "Retrofit详解(上)"
[17]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/SourceAnalysis/Netowork/Retrofit%E8%AF%A6%E8%A7%A3(%E4%B8%8B).md "Retrofit详解(下)"
[18]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/VideoDevelopment/%E6%90%AD%E5%BB%BAnginx%2Brtmp%E6%9C%8D%E5%8A%A1%E5%99%A8.md "搭建nginx+rtmp服务器"
[19]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/VideoDevelopment/%E8%A7%86%E9%A2%91%E6%92%AD%E6%94%BE%E7%9B%B8%E5%85%B3%E5%86%85%E5%AE%B9%E6%80%BB%E7%BB%93.md "视频播放相关内容总结"
[20]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/VideoDevelopment/%E8%A7%86%E9%A2%91%E8%A7%A3%E7%A0%81%E4%B9%8B%E8%BD%AF%E8%A7%A3%E4%B8%8E%E7%A1%AC%E8%A7%A3.md "视频解码之软解与硬解"
[21]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/VideoDevelopment/%E9%9F%B3%E8%A7%86%E9%A2%91%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86.md "音视频基础知识"
[22]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/VideoDevelopment/Android%20WebRTC%E7%AE%80%E4%BB%8B.md "Android WebRTC简介"
[23]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/VideoDevelopment/Android%E9%9F%B3%E8%A7%86%E9%A2%91%E5%BC%80%E5%8F%91.md "Android音视频开发知识"
[24]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/VideoDevelopment/DLNA%E7%AE%80%E4%BB%8B.md "DLNA简介"
[25]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/ImageLoaderLibrary/Glide%E7%AE%80%E4%BB%8B(%E4%B8%8A).md "Glide简介(上)"
[26]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/ImageLoaderLibrary/Glide%E7%AE%80%E4%BB%8B(%E4%B8%8B).md "Glide简介(下)"
[27]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/ImageLoaderLibrary/%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93%E6%AF%94%E8%BE%83.md "图片加载库比较"
[28]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/RxJavaPart/1.RxJava%E8%AF%A6%E8%A7%A3(%E4%B8%80).md "RxJava详解(一)"
[29]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/RxJavaPart/2.RxJava%E8%AF%A6%E8%A7%A3(%E4%BA%8C).md "RxJava详解(二)"
[30]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/RxJavaPart/3.RxJava%E8%AF%A6%E8%A7%A3(%E4%B8%89).md "RxJava详解(三)"
[31]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/RxJavaPart/7.RxJava%E7%B3%BB%E5%88%97%E5%85%A8%E5%AE%B6%E6%A1%B6.md "RxJava系列全家桶"
[32]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Tools%26Library/%E7%9B%AE%E5%89%8D%E6%B5%81%E8%A1%8C%E7%9A%84%E5%BC%80%E5%8F%91%E7%BB%84%E5%90%88.md "目前流行的开发组合"
[33]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Tools%26Library/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E7%9B%B8%E5%85%B3%E5%B7%A5%E5%85%B7.md "性能优化相关工具"
[34]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Tools%26Library/Android%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7%E5%8F%8A%E7%B1%BB%E5%BA%93.md "Android开发工具及类库"
[35]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Tools%26Library/Github%E4%B8%AA%E4%BA%BA%E4%B8%BB%E9%A1%B5%E7%BB%91%E5%AE%9A%E5%9F%9F%E5%90%8D.md "Github个人主页绑定域名"
[36]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Tools%26Library/Markdown%E5%AD%A6%E4%B9%A0%E6%89%8B%E5%86%8C.md "Markdown学习手册"
[37]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Tools%26Library/MAT%E5%86%85%E5%AD%98%E5%88%86%E6%9E%90.md "MAT内存分析"
[38]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E4%B8%80).md "Kotlin学习教程(一)(未完)"
[39]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Gradle%26Maven/Gradle%E4%B8%93%E9%A2%98.md "Gradle专题"
[40]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Gradle%26Maven/%E5%8F%91%E5%B8%83library%E5%88%B0Maven%E4%BB%93%E5%BA%93.md "发布library到Maven仓库"
[41]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AppPublish/Android%E5%BA%94%E7%94%A8%E5%8F%91%E5%B8%83.md "Android应用发布"
[42]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AppPublish/Zipalign%E4%BC%98%E5%8C%96.md "Zipalign优化"
[43]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//SourceAnalysis "源码解析"
[44]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//VideoDevelopment "音视频开发"
[45]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//ImageLoaderLibrary "图片加载"
[46]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//RxJavaPart "RxJava"
[47]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//Tools%26Library "开发工具"
[48]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//KotlinCourse "Kotlin学习"
[49]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//Gradle%26Maven "Gradle&Maven"
[50]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//AppPublish "应用发布"
[51]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//AndroidStudioCourse "Android Studio使用教程"
[52]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//AdavancedPart "进阶部分"
[53]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//JavaKnowledge "Java基础及算法"
[54]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//BasicKnowledge "基础部分"
[55]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B(%E7%AC%AC%E4%B8%80%E5%BC%B9).md "AndroidStudio使用教程(第一弹)"
[56]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B(%E7%AC%AC%E4%BA%8C%E5%BC%B9).md "AndroidStudio使用教程(第二弹)"
[57]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B(%E7%AC%AC%E4%B8%89%E5%BC%B9).md "AndroidStudio使用教程(第三弹)"
[58]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B(%E7%AC%AC%E5%9B%9B%E5%BC%B9).md "AndroidStudio使用教程(第四弹)"
[59]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B(%E7%AC%AC%E4%BA%94%E5%BC%B9).md "AndroidStudio使用教程(第五弹)"
[60]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B(%E7%AC%AC%E5%85%AD%E5%BC%B9).md "AndroidStudio使用教程(第六弹)"
[61]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B(%E7%AC%AC%E4%B8%83%E5%BC%B9).md "AndroidStudio使用教程(第七弹)"
[62]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/Android%20Studio%E4%BD%A0%E5%8F%AF%E8%83%BD%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84%E6%93%8D%E4%BD%9C.md "Android Studio你可能不知道的操作"
[63]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E6%8F%90%E9%AB%98Build%E9%80%9F%E5%BA%A6.md "AndroidStudio提高Build速度"
[64]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio%E4%B8%AD%E8%BF%9B%E8%A1%8Cndk%E5%BC%80%E5%8F%91.md "AndroidStudio中进行ndk开发"
[65]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/%E5%B8%83%E5%B1%80%E4%BC%98%E5%8C%96.md "布局优化"
[66]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/%E5%B1%8F%E5%B9%95%E9%80%82%E9%85%8D%E4%B9%8B%E7%99%BE%E5%88%86%E6%AF%94%E6%96%B9%E6%A1%88%E8%AF%A6%E8%A7%A3.md "屏幕适配之百分比方案详解"
[67]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/%E7%83%AD%E4%BF%AE%E5%A4%8D%E5%AE%9E%E7%8E%B0.md "热修复实现"
[68]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/%E5%A6%82%E4%BD%95%E8%AE%A9Service%E5%B8%B8%E9%A9%BB%E5%86%85%E5%AD%98.md "如何让Service常驻内存"
[69]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/%E9%80%9A%E8%BF%87Hardware%20Layer%E6%8F%90%E9%AB%98%E5%8A%A8%E7%94%BB%E6%80%A7%E8%83%BD.md "通过Hardware Layer提高动画性能"
[70]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96.md "性能优化"
[71]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/%E6%B3%A8%E8%A7%A3%E4%BD%BF%E7%94%A8.md "注解使用"
[72]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Android6.0%E6%9D%83%E9%99%90%E7%B3%BB%E7%BB%9F.md "Android6.0权限系统"
[73]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Android%E5%BC%80%E5%8F%91%E4%B8%8D%E7%94%B3%E8%AF%B7%E6%9D%83%E9%99%90%E6%9D%A5%E4%BD%BF%E7%94%A8%E5%AF%B9%E5%BA%94%E5%8A%9F%E8%83%BD.md "Android开发不申请权限来使用对应功能"
[74]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Android%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84MVP%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3.md "Android开发中的MVP模式详解"
[75]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Android%E5%90%AF%E5%8A%A8%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3.md "Android启动模式详解"
[76]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Android%E5%8D%B8%E8%BD%BD%E5%8F%8D%E9%A6%88.md "Android卸载反馈"
[77]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/ApplicationId%20vs%20PackageName.md "ApplicationId vs PackageName"
[78]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/ART%E4%B8%8EDalvik.md "ART与Dalvik"
[79]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/BroadcastReceiver%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98.md "BroadcastReceiver安全问题"
[80]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Handler%E5%AF%BC%E8%87%B4%E5%86%85%E5%AD%98%E6%B3%84%E9%9C%B2%E5%88%86%E6%9E%90.md "Handler导致内存泄露分析"
[81]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Library%E9%A1%B9%E7%9B%AE%E4%B8%AD%E8%B5%84%E6%BA%90id%E4%BD%BF%E7%94%A8case%E6%97%B6%E6%8A%A5%E9%94%99.md "Library项目中资源id使用case时报错"
[82]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Mac%E4%B8%8B%E9%85%8D%E7%BD%AEadb%E5%8F%8AAndroid%E5%91%BD%E4%BB%A4.md "Mac下配置adb及Android命令"
[83]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/MaterialDesign%E4%BD%BF%E7%94%A8.md "MaterialDesign使用"
[84]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/RecyclerView%E4%B8%93%E9%A2%98.md "RecyclerView专题"
[85]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%A4%A7%E5%85%A8.md "常用命令行大全"
[86]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%8D%95%E4%BE%8B%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F.md "单例的最佳实现方式"
[87]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md "数据结构"
[88]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E8%8E%B7%E5%8F%96%E4%BB%8A%E5%90%8E%E5%A4%9A%E5%B0%91%E5%A4%A9%E5%90%8E%E7%9A%84%E6%97%A5%E6%9C%9F.md "获取今后多少天后的日期"
[89]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%89%91%E6%8C%87Offer(%E4%B8%8A).md "剑指Offer(上)"
[90]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/剑指Offer(下).md "剑指Offer(下)"
[91]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%BC%BA%E5%BC%95%E7%94%A8%E3%80%81%E8%BD%AF%E5%BC%95%E7%94%A8%E3%80%81%E5%BC%B1%E5%BC%95%E7%94%A8%E3%80%81%E8%99%9A%E5%BC%95%E7%94%A8.md "强引用、软引用、弱引用、虚引用"
[92]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85.md "生产者消费者"
[93]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E6%95%B0%E6%8D%AE%E5%8A%A0%E5%AF%86%E5%8F%8A%E8%A7%A3%E5%AF%86.md "数据加密及解密"
[94]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E6%AD%BB%E9%94%81.md "死锁"
[95]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95.md "算法"
[96]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E7%BD%91%E7%BB%9C%E8%AF%B7%E6%B1%82%E7%9B%B8%E5%85%B3%E5%86%85%E5%AE%B9%E6%80%BB%E7%BB%93.md "网络请求相关内容总结"
[97]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E5%8E%9F%E7%90%86.md "线程池的原理"
[98]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%8E%9F%E5%AD%90%E6%80%A7%E3%80%81%E5%8F%AF%E8%A7%81%E6%80%A7%E4%BB%A5%E5%8F%8A%E6%9C%89%E5%BA%8F%E6%80%A7.md "原子性、可见性以及有序性"
[99]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/Base64%E5%8A%A0%E5%AF%86.md "Base64加密"
[100]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/Git%E7%AE%80%E4%BB%8B.md "Git简介"
[101]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/hashCode%E4%B8%8Eequals.md "hashCode与equals"
[102]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/HashMap%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90.md "HashMap实现原理分析"
[103]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/Java%E5%9F%BA%E7%A1%80%E9%9D%A2%E8%AF%95%E9%A2%98.md "Java基础面试题"
[104]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/JVM%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E6%9C%BA%E5%88%B6.md "JVM垃圾回收机制"
[105]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/MD5%E5%8A%A0%E5%AF%86.md "MD5加密"
[106]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/MVC%E4%B8%8EMVP%E5%8F%8AMVVM.md "MVC与MVP及MVVM"
[107]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/RMB%E5%A4%A7%E5%B0%8F%E5%86%99%E8%BD%AC%E6%8D%A2.md "RMB大小写转换"
[108]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/Vim%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B.md "Vim使用教程"
[109]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/volatile%E5%92%8CSynchronized%E5%8C%BA%E5%88%AB.md "volatile和Synchronized区别"
[110]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%AE%89%E5%85%A8%E9%80%80%E5%87%BA%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F.md "安全退出应用程序"
[111]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E7%97%85%E6%AF%92.md "病毒"
[112]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%B6%85%E7%BA%A7%E7%AE%A1%E7%90%86%E5%91%98(DevicePoliceManager).md "超级管理员(DevicePoliceManager)"
[113]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%90%AF%E5%8A%A8%E3%80%81%E5%8D%B8%E8%BD%BD%E5%92%8C%E5%88%86%E4%BA%AB.md "程序的启动、卸载和分享"
[114]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E4%BB%A3%E7%A0%81%E6%B7%B7%E6%B7%86.md "代码混淆"
[115]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%AF%BB%E5%8F%96%E7%94%A8%E6%88%B7logcat%E6%97%A5%E5%BF%97.md "读取用户logcat日志"
[116]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E7%9F%AD%E4%BF%A1%E5%B9%BF%E6%92%AD%E6%8E%A5%E6%94%B6%E8%80%85.md "短信广播接收者"
[117]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%96%AD%E7%82%B9%E4%B8%8B%E8%BD%BD.md "多线程断点下载"
[118]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E9%BB%91%E5%90%8D%E5%8D%95%E6%8C%82%E6%96%AD%E7%94%B5%E8%AF%9D%E5%8F%8A%E5%88%A0%E9%99%A4%E7%94%B5%E8%AF%9D%E8%AE%B0%E5%BD%95.md "黑名单挂断电话及删除电话记录"
[119]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%A8%AA%E5%90%91ListView.md "横向ListView"
[120]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%BB%91%E5%8A%A8%E5%88%87%E6%8D%A2Activity(GestureDetector).md "滑动切换Activity(GestureDetector)"
[121]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%8E%B7%E5%8F%96%E8%81%94%E7%B3%BB%E4%BA%BA.md "获取联系人"
[122]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%8E%B7%E5%8F%96%E6%89%8B%E6%9C%BA%E5%8F%8ASD%E5%8D%A1%E5%8F%AF%E7%94%A8%E5%AD%98%E5%82%A8%E7%A9%BA%E9%97%B4.md "获取手机及SD卡可用存储空间"
[123]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%8E%B7%E5%8F%96%E6%89%8B%E6%9C%BA%E4%B8%AD%E6%89%80%E6%9C%89%E5%AE%89%E8%A3%85%E7%9A%84%E7%A8%8B%E5%BA%8F.md "获取手机中所有安装的程序"
[124]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%8E%B7%E5%8F%96%E4%BD%8D%E7%BD%AE(LocationManager).md "获取位置(LocationManager)"
[125]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%8E%B7%E5%8F%96%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%BC%93%E5%AD%98%E5%8F%8A%E4%B8%80%E9%94%AE%E6%B8%85%E7%90%86.md "获取应用程序缓存及一键清理"
[126]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%BC%80%E5%8F%91%E4%B8%AD%E5%BC%82%E5%B8%B8%E7%9A%84%E5%A4%84%E7%90%86.md "开发中异常的处理"
[127]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%BC%80%E5%8F%91%E4%B8%ADLog%E7%9A%84%E7%AE%A1%E7%90%86.md "开发中Log的管理"
[128]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%BF%AB%E6%8D%B7%E6%96%B9%E5%BC%8F%E5%B7%A5%E5%85%B7%E7%B1%BB.md "快捷方式工具类"
[129]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%9D%A5%E7%94%B5%E5%8F%B7%E7%A0%81%E5%BD%92%E5%B1%9E%E5%9C%B0%E6%8F%90%E7%A4%BA%E6%A1%86.md "来电号码归属地提示框"
[130]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%9D%A5%E7%94%B5%E7%9B%91%E5%90%AC%E5%8F%8A%E5%BD%95%E9%9F%B3.md "来电监听及录音"
[131]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E9%9B%B6%E6%9D%83%E9%99%90%E4%B8%8A%E4%BC%A0%E6%95%B0%E6%8D%AE.md "零权限上传数据"
[132]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F.md "内存泄漏"
[133]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%B1%8F%E5%B9%95%E9%80%82%E9%85%8D.md "屏幕适配"
[134]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8(ActivityManager).md "任务管理器(ActivityManager)"
[135]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%89%8B%E6%9C%BA%E6%91%87%E6%99%83.md "手机摇晃"
[136]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E7%AB%96%E7%9D%80%E7%9A%84Seekbar.md "竖着的Seekbar"
[137]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8.md "数据存储"
[138]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%90%9C%E7%B4%A2%E6%A1%86.md "搜索框"
[139]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E9%94%81%E5%B1%8F%E4%BB%A5%E5%8F%8A%E8%A7%A3%E9%94%81%E7%9B%91%E5%90%AC.md "锁屏以及解锁监听"
[140]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.md "文件上传"
[141]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E4%B8%8B%E6%8B%89%E5%88%B7%E6%96%B0ListView.md "下拉刷新ListView"
[142]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E4%BF%AE%E6%94%B9%E7%B3%BB%E7%BB%9F%E7%BB%84%E4%BB%B6%E6%A0%B7%E5%BC%8F.md "修改系统组件样式"
[143]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E9%9F%B3%E9%87%8F%E5%8F%8A%E5%B1%8F%E5%B9%95%E4%BA%AE%E5%BA%A6%E8%B0%83%E8%8A%82.md "音量及屏幕亮度调节"
[144]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%BA%94%E7%94%A8%E5%AE%89%E8%A3%85.md "应用安装"
[145]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E5%BA%94%E7%94%A8%E5%90%8E%E5%8F%B0%E5%94%A4%E9%86%92%E5%90%8E%E6%95%B0%E6%8D%AE%E7%9A%84%E5%88%B7%E6%96%B0.md "应用后台唤醒后数据的刷新"
[146]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E7%9F%A5%E8%AF%86%E5%A4%A7%E6%9D%82%E7%83%A9.md "知识大杂烩"
[147]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6%E6%8B%B7%E8%B4%9D%E7%9A%84%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F.md "资源文件拷贝的三种方式"
[148]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%87%AA%E5%AE%9A%E4%B9%89%E8%83%8C%E6%99%AF.md "自定义背景"
[149]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6.md "自定义控件"
[150]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%87%AA%E5%AE%9A%E4%B9%89%E7%8A%B6%E6%80%81%E6%A0%8F%E9%80%9A%E7%9F%A5.md "自定义状态栏通知"
[151]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/%E8%87%AA%E5%AE%9A%E4%B9%89Toast.md "自定义Toast"
[152]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/adb%20logcat%E4%BD%BF%E7%94%A8%E7%AE%80%E4%BB%8B.md "adb logcat使用简介"
[153]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Android%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83.md "Android编码规范"
[154]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Android%E5%8A%A8%E7%94%BB.md "Android动画"
[155]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Android%E5%9F%BA%E7%A1%80%E9%9D%A2%E8%AF%95%E9%A2%98.md "Android基础面试题"
[156]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Android%E5%85%A5%E9%97%A8%E4%BB%8B%E7%BB%8D.md "Android入门介绍"
[157]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Android%E5%9B%9B%E5%A4%A7%E7%BB%84%E4%BB%B6%E4%B9%8BContentProvider.md "Android四大组件之ContentProvider"
[158]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Android%E5%9B%9B%E5%A4%A7%E7%BB%84%E4%BB%B6%E4%B9%8BService.md "Android四大组件之Service"
[159]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Ant%E6%89%93%E5%8C%85.md "Ant打包"
[160]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Bitmap%E4%BC%98%E5%8C%96.md "Bitmap优化"
[161]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Fragment%E4%B8%93%E9%A2%98.md "Fragment专题"
[162]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Home%E9%94%AE%E7%9B%91%E5%90%AC.md "Home键监听"
[163]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/HttpClient%E6%89%A7%E8%A1%8CGet%E5%92%8CPost%E8%AF%B7%E6%B1%82.md "HttpClient执行Get和Post请求"
[164]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/JNI_C%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80.md "JNI_C语言基础"
[165]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/JNI%E5%9F%BA%E7%A1%80.md "JNI基础"
[166]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/ListView%E4%B8%93%E9%A2%98.md "ListView专题"
[167]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Parcelable%E5%8F%8ASerializable.md "Parcelable及Serializable"
[168]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/PopupWindow%E7%BB%86%E8%8A%82.md "PopupWindow细节"
[169]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Scroller%E7%AE%80%E4%BB%8B.md "Scroller简介"
[170]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/ScrollingTabs.md "ScrollingTabs"
[171]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/SDK%20Manager%E6%97%A0%E6%B3%95%E6%9B%B4%E6%96%B0%E7%9A%84%E9%97%AE%E9%A2%98.md "SDK Manager无法更新的问题"
[172]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Selector%E4%BD%BF%E7%94%A8.md "Selector使用"
[173]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/SlidingMenu.md "SlidingMenu"
[174]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/String%E6%A0%BC%E5%BC%8F%E5%8C%96.md "String格式化"
[175]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/TextView%E8%B7%91%E9%A9%AC%E7%81%AF%E6%95%88%E6%9E%9C.md "TextView跑马灯效果"
[176]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/WebView%E6%80%BB%E7%BB%93.md "WebView总结"
[177]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Widget(%E7%AA%97%E5%8F%A3%E5%B0%8F%E9%83%A8%E4%BB%B6).md "Widget(窗口小部件)"
[178]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/Wifi%E7%8A%B6%E6%80%81%E7%9B%91%E5%90%AC.md "Wifi状态监听"
[179]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/BasicKnowledge/XmlPullParser.md "XmlPullParser"
[180]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E4%B8%80).md "Kotlin学习教程(一)"
[181]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E4%BA%8C).md "Kotlin学习教程(二)"
[182]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E4%B8%89).md "Kotlin学习教程(三)"
[183]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E5%9B%9B).md "Kotlin学习教程(四)"
[184]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E4%BA%94).md "Kotlin学习教程(五)"
[185]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E5%85%AD).md "Kotlin学习教程(六)"
[186]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E4%B8%83).md "Kotlin学习教程(七)"
[187]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E5%85%AB).md "Kotlin学习教程(八)"
[188]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E4%B9%9D).md "Kotlin学习教程(九)"
[189]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%85%AB%E7%A7%8D%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.md "八种排序算法"
[190]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%AE%80%E4%BB%8B.md "线程池简介"
[191]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md "设计模式"
[192]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E7%AE%97%E6%B3%95%E7%9A%84%E5%A4%8D%E6%9D%82%E5%BA%A6.md "算法复杂度"
[193]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86.md "动态代理"
[194]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/ConstraintLaayout%E7%AE%80%E4%BB%8B.md "ConstraintLaayout简介"
[195]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/Http%E4%B8%8EHttps%E7%9A%84%E5%8C%BA%E5%88%AB.md "Http与Https的区别"
[196]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/JavaKnowledge/Top-K%E9%97%AE%E9%A2%98.md "Top-K问题"
[197]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/KotlinCourse/Kotlin%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B(%E5%8D%81).md "Kotlin学习教程(十)"
[198]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AppPublish/%E4%BD%BF%E7%94%A8Jenkins%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E5%8C%96%E6%89%93%E5%8C%85.md "使用Jenkins实现自动化打包"
[199]: https://github.com/pengMaster/BestNote/tree/master/docs/android/AndroidNote//Dagger2 "Dagger2"
[200]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/1.Dagger2%E7%AE%80%E4%BB%8B(%E4%B8%80).md "1.Dagger2简介(一).md"
[201]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/2.Dagger2%E5%85%A5%E9%97%A8demo(%E4%BA%8C).md "2.Dagger2入门demo(二).md"
[202]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/3.Dagger2%E5%85%A5%E9%97%A8demo%E6%89%A9%E5%B1%95(%E4%B8%89).md "3.Dagger2入门demo扩展(三).md"
[203]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/4.Dagger2%E5%8D%95%E4%BE%8B(%E5%9B%9B).md "4.Dagger2单例(四).md"
[204]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/5.Dagger2Lay%E5%92%8CProvider(%E4%BA%94).md "5.Dagger2Lay和Provider(五).md"
[205]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/6.Dagger2Android%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81(%E5%85%AD).md "6.Dagger2Android示例代码(六).md"
[206]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/7.Dagger2%E4%B9%8Bdagger-android(%E4%B8%83).md "7.Dagger2之dagger-android(七).md"
[207]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/8.Dagger2%E4%B8%8EMVP(%E5%85%AB).md "8.Dagger2与MVP(八).md"
[208]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/AdavancedPart/Android%20WorkManager.md "Android WorkManager.md"
[209]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/RxJavaPart/4.RxJava%E8%AF%A6%E8%A7%A3%E4%B9%8B%E6%89%A7%E8%A1%8C%E5%8E%9F%E7%90%86(%E5%9B%9B).md "4.RxJava详解之执行原理(四)"
[210]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/RxJavaPart/5.RxJava%E8%AF%A6%E8%A7%A3%E4%B9%8B%E6%93%8D%E4%BD%9C%E7%AC%A6%E6%89%A7%E8%A1%8C%E5%8E%9F%E7%90%86(%E4%BA%94).md "5.RxJava详解之操作符执行原理(五)"
[211]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/RxJavaPart/6.RxJava%E8%AF%A6%E8%A7%A3%E4%B9%8B%E7%BA%BF%E7%A8%8B%E8%B0%83%E5%BA%A6%E5%8E%9F%E7%90%86(%E5%85%AD).md "6.RxJava详解之线程调度原理(六)"
[212]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Dagger2/9.Dagger2%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90(%E4%B9%9D).md "9.Dagger2原理分析(九)"
[213]: https://github.com/pengMaster/BestNote/blob/master/docs/android/AndroidNote/Tools%26Library/%E8%B0%83%E8%AF%95%E5%B9%B3%E5%8F%B0Sonar.md "调试平台Sonar"
================================================
FILE: docs/.nojekyll
================================================
================================================
FILE: docs/android/Android-Interview/.gitignore
================================================
# Node rules:
## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
## Dependency directory
## Commenting this out is preferred by some people, see
## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git
node_modules
# Book build output
_book
# eBook build output
*.epub
*.mobi
*.pdf
================================================
FILE: docs/android/Android-Interview/Activity/Activity Task和Process.md
================================================
### 源码分析相关面试题
- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)
- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)
- [okhttp3.0源码分析](http://www.jianshu.com/p/9ed2c2f2a52c)
- [onSaveInstanceState源码分析](http://www.jianshu.com/p/cbf9c3557d64)
- [静默安装和源码编译](http://www.jianshu.com/p/2211a5b3c37f)
### Activity相关面试题
- [保存Activity的状态](http://www.jianshu.com/p/cbf9c3557d64)
- [深刻剖析activity启动模式(一)](http://www.jianshu.com/p/b33fd8c550bf)
- [深刻剖析activity启动模式(二)](http://www.jianshu.com/p/e1ea9e542112)
- [深刻剖析activity启动模式(三)](http://www.jianshu.com/p/d13e3d552d4b)
- [Activity Task和Process之间的关系](http://www.jianshu.com/p/d13e3d552d4b)
- [service里面startActivity抛异常?activity不会](http://www.jianshu.com/p/16e880ceb3a4)
### 与XMPP相关面试题
- [XMPP协议优缺点](http://www.jianshu.com/p/2c04ac3c526a)
- [极光消息推送原理](http://www.jianshu.com/p/d88dc66908cf)
### 与性能优化相关面试题
- [内存泄漏和内存溢出区别](http://www.jianshu.com/p/5dd645b05c76)
- [UI优化和线程池实现原理](http://www.jianshu.com/p/c22398f8587f)
- [代码优化](http://www.jianshu.com/p/ebd41eab90df)
- [内存性能分析](http://www.jianshu.com/p/2665c31b9c2f)
- [内存泄漏检测](http://www.jianshu.com/p/1514c7804a06)
- [App启动优化](http://www.jianshu.com/p/f0f73fefdd43)
- [与IPC机制相关面试题](http://www.jianshu.com/p/de4793a4c2d0)
### 与登录相关面试题
- [oauth认证协议原理](http://www.jianshu.com/p/2a6ecbf8d49d)
- [token产生的意义](http://www.jianshu.com/p/9b7ce2d6c195)
- [微信扫一扫实现原理](http://www.jianshu.com/p/a9d1f21bd5e0)
### 与开发相关面试题
- [迭代开发的时候如何向前兼容新旧接口](http://www.jianshu.com/p/cbecadec98de)
- [手把手教你如何解决as jar包冲突](http://www.jianshu.com/p/30fdc391289c)
- [context的原理分析](http://www.jianshu.com/p/2706c13a1769)
- [解决ViewPager.setCurrentItem中间很多页面切换方案](http://www.jianshu.com/p/38ab6d856b56)
- [字体适配](http://www.jianshu.com/p/33d499170e25)
- [软键盘顶出去解决方案](http://www.jianshu.com/p/640bac6f58ab)与人事相关面试题
- [人事面试宝典](http://www.jianshu.com/p/d61b553ff8c9)
AMS提供了一个ArrayList mHistory来管理所有的activity,activity在AMS中的形式是ActivityRecord,task在AMS中的形式为TaskRecord,进程在AMS中的管理形式为ProcessRecord。如下图所示

从图中我们可以看出如下几点规则:
1) 所有的ActivityRecord会被存储在mHistory管理;
2) 每个ActivityRecord会对应到一个TaskRecord,并且有着相同TaskRecord的ActivityRecord在mHistory中会处在连续的位置;
3) 同一个TaskRecord的Activity可能分别处于不同的进程中,每个Activity所处的进程跟task没有关系;
Activity启动时ActivityManagerService会为其生成对应的ActivityRecord记录,并将其加入到回退栈(back stack)中,另外也会将ActivityRecord记录加入到某个Task中。请记住,ActivityRecord,backstack,Task都是ActivityManagerService的对象,由ActivityManagerService进程负责维护,而不是由应用进程维护。
在回退栈里属于同一个task的ActivityRecord会放在一起,也会形成栈的结构,也就是说后启动的Activity对应的ActivityRecord会放在task的栈顶
执行adb shell dumpsys activity命令,发现有以下输出:
```
Task id #30
TaskRecord{7f2f34a #30 A=com.maweiqi.second U=0 sz=2}
Intent { flg=0x10000000 cmp=com.open.android.task1/.SecondActivity }
Hist #1: ActivityRecord{a0f9ded u0 com.open.android.task3/.OtherActivity t30}
Intent { flg=0x10400000 cmp=com.open.android.task3/.OtherActivity }
ProcessRecord{12090b5 27543:com.open.android.task3/u0a62}
Hist #0: ActivityRecord{1048af6 u0 com.open.android.task1/.SecondActivity t30}
Intent { flg=0x10000000 cmp=com.open.android.task1/.SecondActivity }
ProcessRecord{5bc013e 26035:com.open.android.task1/u0a59}
Task id #31
TaskRecord{dce52bb #31 A=com.open.android.task3 U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task3/.MainActivity }
Hist #0: ActivityRecord{f9e58c5 u0 com.open.android.task3/.MainActivity t31}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task3/.MainActivity }
ProcessRecord{12090b5 27543:com.open.android.task3/u0a62}
Task id #29
TaskRecord{5b063d8 #29 A=com.open.android.task1 U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task1/.MainActivity }
Hist #0: ActivityRecord{689947d u0 com.open.android.task1/.MainActivity t29}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task1/.MainActivity }
ProcessRecord{5bc013e 26035:com.open.android.task1/u0a59}
Running activities (most recent first):
TaskRecord{7f2f34a #30 A=com.maweiqi.second U=0 sz=2}
Run #3: ActivityRecord{a0f9ded u0 com.open.android.task3/.OtherActivity t30}
TaskRecord{dce52bb #31 A=com.open.android.task3 U=0 sz=1}
Run #2: ActivityRecord{f9e58c5 u0 com.open.android.task3/.MainActivity t31}
TaskRecord{7f2f34a #30 A=com.maweiqi.second U=0 sz=2}
Run #1: ActivityRecord{1048af6 u0 com.open.android.task1/.SecondActivity t30}
TaskRecord{5b063d8 #29 A=com.open.android.task1 U=0 sz=1}
Run #0: ActivityRecord{689947d u0 com.open.android.task1/.MainActivity t29}
mResumedActivity: ActivityRecord{a0f9ded u0 com.open.android.task3/.OtherActivity t30}
```
从图对应文字在对应adb输出,这几个基本概念大家估计就清楚了。
- 欢迎关注微信公众号,长期推荐技术文章和技术视频
- 微信公众号名称:Android干货程序员

================================================
FILE: docs/android/Android-Interview/Activity/App优雅退出.md
================================================
### **1. RxBus优雅式**
首先,在基类BaseActivity里,注册RxBus监听:
```java
public class BaseActivity3 extends AppCompatActivity {
Subscription mSubscription;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initRxBus();
}
//接收退出的指令,关闭所有activity
private void initRxBus() {
mSubscription = RxBus.getInstance().toObserverable(NormalEvent.class)
.subscribe(new Action1<NormalEvent>() {
@Override
public void call(NormalEvent userEvent) {
if (userEvent.getType() == -1) {
finish();
}
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!mSubscription.isUnsubscribed()) {
mSubscription.unsubscribe();
}
}
}
```
这是事件实体NormalEvent:
```java
public class NormalEvent {
private int type;
public NormalEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
```
新建RxBus类
```java
public class RxBus {
private static volatile RxBus mInstance;
private final Subject bus;
public RxBus()
{
bus = new SerializedSubject<>(PublishSubject.create());
}
/**
* 单例模式RxBus
*
* @return
*/
public static RxBus getInstance()
{
RxBus rxBus2 = mInstance;
if (mInstance == null)
{
synchronized (RxBus.class)
{
rxBus2 = mInstance;
if (mInstance == null)
{
rxBus2 = new RxBus();
mInstance = rxBus2;
}
}
}
return rxBus2;
}
/**
* 发送消息
*
* @param object
*/
public void post(Object object)
{
bus.onNext(object);
}
/**
* 接收消息
*
* @param eventType
* @param <T>
* @return
*/
public <T> Observable<T> toObserverable(Class<T> eventType)
{
return bus.ofType(eventType);
}
}
```
最后,在需要退出的地方调用:
```java
RxBus.getInstance().post(new NormalEvent(-1));//发送退出指令
```
### **2. 容器式:**
建立一个全局容器,把所有的Activity存储起来,退出时循环遍历finish所有Activity
```java
public class BaseActivity extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
ActivityManager.getActivityManager().addActivity(this);
}
@Override protected void onDestroy() {
super.onDestroy();
// 结束Activity&从栈中移除该Activity
ActivityManager.getActivityManager().finishActivity();
}
}
public class ActivityManager {
// Activity栈
private static Stack<Activity> activityStack;
// 单例模式
private static ActivityManager instance;
private ActivityManager() {
}
/**
* 单一实例
*/
public static ActivityManager getActivityManager() {
if (instance == null) {
instance = new ActivityManager();
}
return instance;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
if (activityStack == null) {
activityStack = new Stack<Activity>();
}
activityStack.add(activity);
}
/**
* 获取当前Activity(堆栈中最后一个压入的)
*/
public Activity currentActivity() {
Activity activity = activityStack.lastElement();
return activity;
}
/**
* 结束当前Activity(堆栈中最后一个压入的)
*/
public void finishActivity() {
Activity activity = activityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity) {
if (activity != null) {
activityStack.remove(activity);
activity.finish();
activity = null;
}
}
/**
* 结束指定类名的Activity
*/
public void finishActivity(Class<?> cls) {
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
finishActivity(activity);
}
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (int i = 0; i < activityStack.size(); i++) {
if (null != activityStack.get(i)) {
activityStack.get(i).finish();
}
}
activityStack.clear();
}
/**
* 退出应用程序
*/
public void AppExit(Context context) {
try {
finishAllActivity();
//根据进程ID,杀死该进程
android.os.Process.killProcess(android.os.Process.myPid());
//退出真个应用程序
System.exit(0);
} catch (Exception e) {
}
}
}
```
### **3. 广播式**
通过在BaseActivity中注册一个广播,当退出时发送一个广播,finish退出
```java
public class BaseActivity2 extends AppCompatActivity {
private static final String EXITACTION = "action.exit";
private ExitReceiver exitReceiver = new ExitReceiver();
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter();
filter.addAction(EXITACTION);
registerReceiver(exitReceiver, filter);
}
@Override protected void onDestroy() {
super.onDestroy(); unregisterReceiver(exitReceiver);
}
class ExitReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
BaseActivity2.this.finish();
}
}
}
```
### **4. SingleTask**
1、设置MainActivity的加载模式为singleTask
```xml
android:launchMode="singleTask"
```
2、将退出出口放置在MainActivity
```java
private boolean mIsExit;
@Override /** * 双击返回键退出 */
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mIsExit) {
this.finish();
} else {
Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
mIsExit = true;
new Handler().postDelayed(new Runnable() {
@Override public void run() {
mIsExit = false;
}
}, 2000);
} return true;
} return super.onKeyDown(keyCode, event);
}
```
### **5. SingleTask改版式**
第一步设置MainActivity的加载模式为singleTask
```xml
android:launchMode="singleTask"
```
第二步重写onNewIntent()方法
```java
private static final String TAG_EXIT = "exit";
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent != null) {
boolean isExit = intent.getBooleanExtra(TAG_EXIT, false);
if (isExit) { this.finish();
}
}
}
```
第三步 退出
```java
Intent intent = new Intent(this,MainActivity.class); intent.putExtra(MainActivity.TAG_EXIT, true);
startActivity(intent);
```
================================================
FILE: docs/android/Android-Interview/Activity/README.md
================================================
## Activity相关面试题
- [onSaveInstanceState源码内核分析](onSaveInstanceState源码内核分析.md)
- [深刻剖析activity启动模式-1](深刻剖析activity启动模式-1.md)
- [深刻剖析activity启动模式-2](深刻剖析activity启动模式-2.md)
- [深刻剖析activity启动模式-3](深刻剖析activity启动模式-3.md)
- [Activity Task和Process之间的关系](Activity Task和Process.md)
- [为什么service里面startActivity抛异常](为什么service里面startActivity抛异常.md)
- [App优雅退出](Android面试题-app优雅退出.md)
- [onCreate源码分析](onCreate源码分析.md)
================================================
FILE: docs/android/Android-Interview/Activity/onCreate源码分析.md
================================================
Activity扮演了一个界面展示的角色,堪称四大组件之首,onCreate是Activity的执行入口,都不知道入口到底干了嘛,还学什么android,所以本文会从源码的角度对其进行分析。
熟悉源码的会发现,真正启动Activity的实现都在ActivityThread,前面的调用过程略过
ActivityThread的方法performLaunchActivity中调用了Instrumentation类中的方法callActivityOnCreate方法,继而调用了TargetActivity中的onCreate方法。
```java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Activity activity = null;
activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
......
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
......
}
```
#### **源码可知:**
1)通过反射的机制创建的Activity
2)这里的mInstrumentation是类Instrumentation
3)Instrumentation类中的方法callActivityOnCreate方法源码如下:
```java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
```
#### **源码可知:**
1)activity.performCreate(icicle),其中的方法是通过activity,这个activity,形如:Activity activity = 子Activity的对象
2)在Activity类中的方法performCreate(icicle),源码如下:
```java
final void performCreate(Bundle icicle) {
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
```
#### **源码可知:**
1)原来onCreate的生命周期方法是在这里回调的
2)在performCreate方法中调用的onCreate方法是MainActivity中的onCreate方法,那么到此MainActivity中的方法onCreate方法中的参数Bundle savedInstanceState也就知道来源了,此时,MainActivity中的方法也就被调用了。
再次看MainActivity中的方法onCreate:
```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
```
super.onCreate(savedInstanceState),其实这条语句放在子类中的onCreate方法中的任何位置都可,问题只是super.onCreate(savedInstanceState)必须要被执行,所以,最好也就是放在第一行,看起来比较明确,至于为什么,参考[onSaveInstanceState源码分析](http://www.jianshu.com/p/cbf9c3557d64)
至此onCreate源码分析完毕。
================================================
FILE: docs/android/Android-Interview/Activity/onSaveInstanceState源码内核分析.md
================================================
### 源码分析相关面试题
- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)
- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)
- [okhttp3.0源码分析](http://www.jianshu.com/p/9ed2c2f2a52c)
- [onSaveInstanceState源码分析](http://www.jianshu.com/p/cbf9c3557d64)
- [静默安装和源码编译](http://www.jianshu.com/p/2211a5b3c37f)
### Activity相关面试题
- [保存Activity的状态](http://www.jianshu.com/p/cbf9c3557d64)
### 与XMPP相关面试题
- [XMPP协议优缺点](http://www.jianshu.com/p/2c04ac3c526a)
- [极光消息推送原理](http://www.jianshu.com/p/d88dc66908cf)
### 与性能优化相关面试题
- [内存泄漏和内存溢出区别](http://www.jianshu.com/p/5dd645b05c76)
- [UI优化和线程池实现原理](http://www.jianshu.com/p/c22398f8587f)
- [代码优化](http://www.jianshu.com/p/ebd41eab90df)
- [内存性能分析](http://www.jianshu.com/p/2665c31b9c2f)
- [内存泄漏检测](http://www.jianshu.com/p/1514c7804a06)
- [App启动优化](http://www.jianshu.com/p/f0f73fefdd43)
- [与IPC机制相关面试题](http://www.jianshu.com/p/de4793a4c2d0)
### 与登录相关面试题
- [oauth认证协议原理](http://www.jianshu.com/p/2a6ecbf8d49d)
- [token产生的意义](http://www.jianshu.com/p/9b7ce2d6c195)
- [微信扫一扫实现原理](http://www.jianshu.com/p/a9d1f21bd5e0)
### 与开发相关面试题
- [迭代开发的时候如何向前兼容新旧接口](http://www.jianshu.com/p/cbecadec98de)
- [手把手教你如何解决as jar包冲突](http://www.jianshu.com/p/30fdc391289c)
- [context的原理分析](http://www.jianshu.com/p/2706c13a1769)
- [解决ViewPager.setCurrentItem中间很多页面切换方案](http://www.jianshu.com/p/38ab6d856b56)
### 与人事相关面试题
- [人事面试宝典](http://www.jianshu.com/p/d61b553ff8c9)
经常有人问,后台的activity被系统自动回收的话,怎么回到界面的时候恢复数据,通过一个真实案例给大家讲讲如何保存状态,然后带着大家分析onSaveInstanceState的源码。

#### **当前页面侧滑菜单指向专题,用户做了如下操作:**
1)当用户按下HOME键时。
2)长按HOME键,选择运行其他的程序时。
3)按下电源按键(关闭屏幕显示)时。
4)从activity A中启动一个新的activity时。
5)屏幕方向切换时,例如从竖屏切换到横屏时。
失去焦点,activity很可能被进程终止!被KILL掉了,这时候就需要能保存当前的状态,不然下次用户再次进来看到的还是新闻,这样用户体验就不够好,代码有删减,我自己项目就这样使用的,解决方案如下:
```java
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt("newsCenter_position", newsCenterPosition);
outState.putInt("smartService_position", smartServicePosition);
outState.putInt("govAffairs_position", govAffairsPosition);
super.onSaveInstanceState(outState);
}
```
#### 如上代码可知:
1)界面被回收之后调用onSaveInstanceState方法保存当前的状态,每个侧滑菜单选项都有一个位置。
```java
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null
&& savedInstanceState.containsKey("newsCenter_position")) {
newsCenterPosition = savedInstanceState
.getInt("newsCenter_position");
smartServicePosition = savedInstanceState
.getInt("smartService_position");
govAffairsPosition = savedInstanceState
.getInt("govAffairs_position");
}
super.onCreate(savedInstanceState);
}
```
#### **由以上代码可知:**
1)判断当前Bundle 是否有刚刚我们保存的位置,如果不为空,从当前的Bundle取出来,给每一个位置赋值。
```java
public void switchMenu(int type) {
switch (type) {
case NEWS_CENTER:
if (newsCenterAdapter == null) {
newsCenterAdapter = new MenuAdapter(ct, newsCenterMenu);
newsCenterclassifyLv.setAdapter(newsCenterAdapter);
} else {
newsCenterAdapter.notifyDataSetChanged();
}
newsCenterAdapter.setSelectedPosition(newsCenterPosition);
break;
case SMART_SERVICE:
if (smartServiceAdapter == null) {
smartServiceAdapter = new MenuAdapter(ct, smartServiceMenu);
smartServiceclassifyLv.setAdapter(smartServiceAdapter);
} else {
smartServiceAdapter.notifyDataSetChanged();
}
smartServiceAdapter.setSelectedPosition(smartServicePosition);
break;
case GOV_AFFAIRS:
if (govAffairsAdapter == null) {
govAffairsAdapter = new MenuAdapter(ct, govAffairsMenu);
govAffairsclassifyLv.setAdapter(govAffairsAdapter);
} else {
govAffairsAdapter.notifyDataSetChanged();
}
govAffairsAdapter.setSelectedPosition(govAffairsPosition);
break;
}
```
#### **以上代码可知:**
1)根据当前的位置设置到adapter当中,这样下次用户进来就还是专题了。
#### **总结下savedInstanceState的使用,代码如下:**
```java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null)
System.out.println("onCreate() : " + savedInstanceState.getString("octopus"));
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
System.out.println("onRestoreInstanceState() : " + savedInstanceState.getString("octopus"));
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("octopus", "www.baidu.com");
System.out.println("onSaveInstanceState() : save date www.baidu.com");
}
}
```
#### **横竖屏切换,打印结果如下:**
```
I/System.out( 8167): onSaveInstanceState() : save date www.baidu.com
I/System.out( 8167): onCreate() : www.baidu.com
I/System.out( 8167): onRestoreInstanceState() : www.baidu.com
```
从打印结果可以看出来,当前Activity被系统回收之后,会调用onSaveInstanceState()保存状态,然后在activity判断bundler是否有当前状态,如果只是到这,估计你们就会吐槽没啥含金量,没办法硬着头皮上,接着咱们来分onSaveInstanceState()源码,请看如下代码:
```java
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
```
#### **以上代码可知**
1)调用父类Activity源码里面的onSaveInstanceState方法,代码如下:
```java
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
......
}
```
#### **以上代码可知**
1)outState.put一个tag调用了mWindow里面的saveHierarchyState方法,继续分析Window源代码。
2)window是抽象类调用子类PhoneWindow里面的saveHierarchyState方法代码如下:
```java
@Override
public Bundle saveHierarchyState() {
Bundle outState = new Bundle();
if (mContentParent == null) {
return outState;
}
SparseArray<Parcelable> states = new SparseArray<Parcelable>();
mContentParent.saveHierarchyState(states);
outState.putSparseParcelableArray(VIEWS_TAG, states);
......
return outState;
}
```
#### **以上代码可知**
1 ) Bundle outState = new Bundle()初始化Bundle对象,Bundle实现了Parcelable接口。
2)states = new SparseArray<Parcelable>()并且把自己放到outState当中。
3)mContentParent.saveHierarchyState(states),整个View树的顶层视图保存了层级状态代码如下:
```java
public void saveHierarchyState(SparseArray<Parcelable> container) {
dispatchSaveInstanceState(container);
}
```
#### 以上代码可知:
1)调相应的dispatchSaveInstanceState方法,代码如下:
```java
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
Parcelable state = onSaveInstanceState();
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onSaveInstanceState()");
}
if (state != null) {
// Log.i("View", "Freezing #" + Integer.toHexString(mID)
// + ": " + state);
container.put(mID, state);
}
}
}
```
#### 以上代码可知:
1) mID != NO_ID 判断一个View必须有一个id,也就是说你要么在xml里通过android:id指定要么在代码里通过setId,但是你从如上代码压根是看不出来谷歌想干啥,必须全局搜索NO_ID 和 mID ,一般在源码里面都会有谷歌工程师的注释方便我们理解,搜索NO_ID 可知代码如下:
```java
/**
* Used to mark a View that has no ID.
*/
public static final int NO_ID = -1;
```
原来NO_ID用来标记没有id的View,搜索mID可知原来在如下代码赋值
```java
public void setId(@IdRes int id) {
mID = id;
if (mID == View.NO_ID && mLabelForId != View.NO_ID) {
mID = generateViewId();
}
}
```
经常当我们看不懂谷歌源码的时候,可以通过曲线救国的方式,看看英文注释,看看源码哪个地方用到当前的类或者方法或者变量,这样就好理解了,好了扯远了,继续分析代码;
2)通过if判断,检测子类是否调用父类的onSaveInstanceState()方法,否则会抛异常,突然看到这才明白,还记得刚刚开始学Android的时候,经常一不小心就把代码里面的super.onCreate(savedInstanceState);这行代码删掉,报了错误还看不懂,原来系统在这里检测了,都怪自己曾经太年轻。
3)container.put(mID, state)这行代码,将state放进SparseArray中,以view自身的id为key,并且从注释来看打印mID的Hex值用来保证每页的id必须是唯一的,难怪每当我给view取id的时候,一个页面有重复的id就会报错,谷歌大婶在这里做判断了,腻害了word哥,总是百思不得其姐,凭啥不让我共用id(因为取名字太难了),原来是想把id做为key来使用。
4)走到这onSaveInstanceState(),调用如下代码:
```java
@CallSuper
protected Parcelable onSaveInstanceState() {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
......
return BaseSavedState.EMPTY_STATE;
}
```
#### 以上代码可知:
1)设置位标志, 默认不save任何东西,状态为空,这就是为啥我们每次随便写个类继承activity实现onCreate方法的时候可以使用参数savedInstanceState保存状态,因为默认为null,代码如下:
```java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
savedInstanceState.putString("key","value");
}
```
至此整个savedInstanceState保存状态源码分析完毕。
- 欢迎关注微信公众号,长期推荐技术文章和技术视频
- 微信公众号名称:Android干货程序员

================================================
FILE: docs/android/Android-Interview/Activity/为什么service里面startActivity抛异常.md
================================================
**Android面试题-源码分析为什么service里面startActivity抛异常?activity不会**
我们有时候需要在service里面启动activity,但是会发现报如下异常:

必须添加FLAG_ACTIVITY_NEW_TASK这个标记就可以了,那么为什么在activity里面不需要呢?接下来通过从源码角度带大家分析。
### **启动activity有两种形式**
1)直接调用Context类的startActivity方法;这种方式启动的Activity没有Activity栈,因此不能以standard方式启动,必须加上FLAG_ACTIVITY_NEW_TASK这个Flag,服务就是通过Context调用。
2)调用被Activity类重载过的startActivity方法,通常在我们的Activity中直接调用这个方法就是这种形式;
### **Context.startActivity源码分析**
我们查看Context类的startActivity方法,发现这竟然是一个抽象类;查看Context的类继承关系图如下:

我们看到诸如Activity,Service等并没有直接继承Context,Activity继承了ContextThemeWrapper,Service而是继承了ContextWrapper;
#### **现在从源码分析ContextWrapper的实现:**
```java
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
```
这个mBase是什么呢?这里我先直接告诉你,它的真正实现是ContextImpl类;至于为什么,有一条思路:在任意mBase打一个断点就能看到实现。
Context.startActivity最终使用了ContextImpl里面的方法,代码如下:
```java
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
```
#### **源码分析:**
1)大家看看抛出来的异常是不是还是熟悉的味道。
2)通过判断可知当前的intent.getFlags是否带有FLAG_ACTIVITY_NEW_TASK这个标记,如果没有抛出异常,因为源码使用了&运算符,只有两个位都是1,结果才是1,所以可知service没有带FLAG_ACTIVITY_NEW_TASK标记,才抛出异常。
3)真正的startActivity使用了Instrumentation类的execStartActivity方法;继续跟踪:
```java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {
......
try {
......
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
```
#### **源码分析:**
1)到这里我们发现真正调用的是ActivityManagerNative的startActivity方法;
### **Activity.startActivity源码分析**
```java
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
```
#### **源码可知:**
1)调用当前类的startActivity方法,代码如下:
```java
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
```
#### **源码可知**
1)调用了startActivityForResult
```java
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
......
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
......
```
#### **源码可知**
1)可以看到,其实通过Activity和ContextImpl类启动Activity并无本质不同,他们都通过Instrumentation这个辅助类调用到了ActivityManagerNative的方法。
2)只是Activity不会去检查标记,所以并不会抛出异常。
至此源码分析完毕。
================================================
FILE: docs/android/Android-Interview/Activity/深入理解Activity启动流程.md
================================================
> 原文链接:[Cloud Chou](http://weibo.com/muguachou). http://www.cloudchou.com/android/post-788.html
## 概述
Android中启动某个Activity,将先启动Activity所在的应用。应用启动时会启动一个以应用包名为进程名的进程,该进程有一个主线程,叫ActivityThread,也叫做UI线程。
本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究。
- [深入理解Activity启动流程(二)--Activity启动相关类的类图](http://www.cloudchou.com/android/post-793.html)
- [深入理解Activity启动流程(三)--Activity启动的详细流程1](http://www.cloudchou.com/android/post-805.html)
- [深入理解Activity启动流程(三)--Activity启动的详细流程2](http://www.cloudchou.com/android/post-815.html)
- [深入理解Activity启动流程(四)--Activity Task的调度算法](http://www.cloudchou.com/android/post-858.html)
## Activity启动时的概要交互流程
用户从Launcher程序点击应用图标可启动应用的入口Activity,Activity启动时需要多个进程之间的交互,Android系统中有一个zygote进程专用于孵化Android框架层和应用层程序的进程。还有一个system_server进程,该进程里运行了很多binder service,例如ActivityManagerService,PackageManagerService,WindowManagerService,这些binder service分别运行在不同的线程中,其中ActivityManagerService负责管理Activity栈,应用进程,task。
Activity启动时的概要交互流程如下图如下所示(点击图片可看[大图](http://www.cloudchou.com/wp-content/uploads/2015/05/activity_start_flow.png)):

用户在Launcher程序里点击应用图标时,会通知ActivityManagerService启动应用的入口Activity,ActivityManagerService发现这个应用还未启动,则会通知Zygote进程孵化出应用进程,然后在这个dalvik应用进程里执行ActivityThread的main方法。应用进程接下来通知ActivityManagerService应用进程已启动,ActivityManagerService保存应用进程的一个代理对象,这样ActivityManagerService可以通过这个代理对象控制应用进程,然后ActivityManagerService通知应用进程创建入口Activity的实例,并执行它的生命周期方法。
================================================
FILE: docs/android/Android-Interview/Activity/深刻剖析activity启动模式-1.md
================================================
### 源码分析相关面试题
- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)
- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)
- [okhttp3.0源码分析](http://www.jianshu.com/p/9ed2c2f2a52c)
- [onSaveInstanceState源码分析](http://www.jianshu.com/p/cbf9c3557d64)
- [静默安装和源码编译](http://www.jianshu.com/p/2211a5b3c37f)
### Activity相关面试题
- [保存Activity的状态](http://www.jianshu.com/p/cbf9c3557d64)
- [深刻剖析activity启动模式(一)](http://www.jianshu.com/p/b33fd8c550bf)
- [深刻剖析activity启动模式(二)](http://www.jianshu.com/p/e1ea9e542112)
### 与XMPP相关面试题
- [XMPP协议优缺点](http://www.jianshu.com/p/2c04ac3c526a)
- [极光消息推送原理](http://www.jianshu.com/p/d88dc66908cf)
### 与性能优化相关面试题
- [内存泄漏和内存溢出区别](http://www.jianshu.com/p/5dd645b05c76)
- [UI优化和线程池实现原理](http://www.jianshu.com/p/c22398f8587f)
- [代码优化](http://www.jianshu.com/p/ebd41eab90df)
- [内存性能分析](http://www.jianshu.com/p/2665c31b9c2f)
- [内存泄漏检测](http://www.jianshu.com/p/1514c7804a06)
- [App启动优化](http://www.jianshu.com/p/f0f73fefdd43)
- [与IPC机制相关面试题](http://www.jianshu.com/p/de4793a4c2d0)
### 与登录相关面试题
- [oauth认证协议原理](http://www.jianshu.com/p/2a6ecbf8d49d)
- [token产生的意义](http://www.jianshu.com/p/9b7ce2d6c195)
- [微信扫一扫实现原理](http://www.jianshu.com/p/a9d1f21bd5e0)
### 与开发相关面试题
- [迭代开发的时候如何向前兼容新旧接口](http://www.jianshu.com/p/cbecadec98de)
- [手把手教你如何解决as jar包冲突](http://www.jianshu.com/p/30fdc391289c)
- [context的原理分析](http://www.jianshu.com/p/2706c13a1769)
- [解决ViewPager.setCurrentItem中间很多页面切换方案](http://www.jianshu.com/p/38ab6d856b56)
### 与人事相关面试题
- [人事面试宝典](http://www.jianshu.com/p/d61b553ff8c9)
### **Activity的四种启动模式如下:**
**standard、singleTop、singleTask、singleInstance**
我们一边讲理论一边结合案例来全面学习这四种启动模式。
为了打印方便,定义一个基础BaseActivity,在其onCreate方法和onNewIntent方法中打印出当前Activity的日志信息,主要包括所属的task,当前类的hashcode,之后我们进行测试的Activity都直接继承该BaseActivity
```java
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("maweiqi", "*****onCreate()方法******");
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
dumpTaskAffinity();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i("maweiqi", "*****onNewIntent()方法*****");
Log.i("maweiqi", "onNewIntent:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
dumpTaskAffinity();
}
protected void dumpTaskAffinity(){
try {
ActivityInfo info = this.getPackageManager()
.getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
Log.i("maweiqi", "taskAffinity:"+info.taskAffinity);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
```
### **standard-默认模式**
这个模式是默认的启动模式,即标准模式,在不指定启动模式的前提下,系统默认使用该模式启动Activity,每次启动一个Activity都会重写创建一个新的实例,不管这个实例存不存在,这种模式下,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中。
#### **配置形式:**
```xml
<activity android:name=".SecondActivity" android:launchMode="standard"/>
```
#### **使用案例:**
对于standard模式,android:launchMode可以不进行声明,因为默认就是standard。 SecondActivity的代码如下,入口MainActivity中有一个按钮进入该Activity,这个Activity中又有一个按钮启动SecondActivity。
```java
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_standard= (Button) findViewById(R.id.btn_standard);
btn_standard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
Log.i("maweiqi", "*****onCreate()方法******");
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
```java
public class SecondActivity extends BaseActivity {
private Button jump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
jump= (Button) findViewById(R.id.button3);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
```
#### **测试方式:**
MainActivity --> SecondActivity --> SecondActivity --> SecondActivity --> SecondActivity
#### **输出的日志如下:**
```
MainActivity TaskId: 2 hasCode:1249333352
SecondActivity TaskId: 2 hasCode:1249526392
SecondActivity TaskId: 2 hasCode:1249424816
SecondActivity TaskId: 2 hasCode:1249439692
SecondActivity TaskId: 2 hasCode:1249459968
```
#### **测试结果:**
1)日志输出了四次SecondActivity的和一次MainActivity的,并且所属的任务栈的id都是2,这也验证了谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中这句话.因为启动SecondActivity的是MainActivity,而MainActivity的taskId是2,因此启动的SecondActivity也应该属于id为2的这个task,后续的3个SecondActivity是被SecondActivity这个对象启动的,因此也应该还是2,所以taskId都是2。
2)并且每一个Activity的hashcode都是不一样的,说明他们是不同的实例,即“每次启动一个Activity都会重写创建一个新的实例”
### **singleTop模式**
这个模式下,如果新的activity已经位于栈顶,那么这个Activity不会被重新创建,同时它的onNewIntent方法会被调用,通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该Activity的实例,则情况与standard模式相同。需要注意的是这个Activity它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变。
#### **配置形式:**
```xml
<activity android:name=".SingleTopActivity" android:launchMode="singleTop"/>
<activity android:name=".OtherTopActivity" android:launchMode="singleTop"/>
```
#### **使用案例:**
```java
public class SingleTopActivity extends BaseActivity {
private Button jump, jump2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_singletop);
jump = (Button) findViewById(R.id.button);
jump2 = (Button) findViewById(R.id.button2);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SingleTopActivity.this, SingleTopActivity.class);
startActivity(intent);
}
});
jump2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SingleTopActivity.this, OtherTopActivity.class);
startActivity(intent);
}
});
Log.i("maweiqi", "*****onCreate()方法******");
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
```java
public class OtherTopActivity extends AppCompatActivity {
private Button jump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
jump= (Button) findViewById(R.id.btn_other);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(OtherTopActivity.this, SingleTopActivity.class);
startActivity(intent);
}
});
Log.i("maweiqi", "*****onCreate()方法******");
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
#### **操作和standard模式类似,直接贴输出日志**
```
onCreate:MainActivity TaskId: 3 hasCode:1249332216
onCreate:SingleTopActivity TaskId: 3 hasCode:1249464444
onNewIntent:SingleTopActivity TaskId: 3 hasCode:1249464444
onNewIntent:SingleTopActivity TaskId: 3 hasCode:1249464444
onNewIntent:SingleTopActivity TaskId: 3 hasCode:1249464444
```
#### **测试结果:**
1)除了第一次进入SingleTopActivity这个Activity时,输出的是onCreate方法中的日志,后续的都是调用了onNewIntent方法,并没有调用onCreate方法,并且四个日志的hashcode都是一样的。
2)说明栈中只有一个实例。这是因为第一次进入的时候,栈中没有该实例,则创建,后续的三次发现栈顶有这个实例,则直接复用,并且调用onNewIntent方法。
3)那么假设栈中有该实例,但是该实例不在栈顶情况又如何呢?
我们先从MainActivity中进入到SingleTopActivity,然后再跳转到OtherActivity中,再从OtherActivity中跳回SingleTopActivity,再从SingleTopActivity跳到SingleTopActivity中,看看整个过程的日志。
#### **输出的日志如下:**
```
onCreate:SingleTopActivity TaskId: 4 hasCode:1249520904
onCreate:OtherTopActivity TaskId: 4 hasCode:1249420244
onCreate:SingleTopActivity TaskId: 4 hasCode:1249448776
onCreate:SingleTopActivity TaskId: 4 hasCode:1249448776
onNewIntent:SingleTopActivity TaskId: 4 hasCode:1249448776
```
#### **测试结果:**
1)从MainActivity进入到SingleTopActivity时,新建了一个SingleTopActivity对象。
2)从SingleTopActivity跳到OtherActivity时,新建了一个OtherActivity,此时task中存在三个Activity,从栈底到栈顶依次是MainActivity,SingleTopActivity,OtherActivity。
3)此时如果再跳到SingleTopActivity,即使栈中已经有SingleTopActivity实例了,但是依然会创建一个新的SingleTopActivity实例,这一点从上面的日志的hashCode可以看出,此时栈顶是SingleTopActivity,如果再跳到SingleTopActivity,就会复用栈顶的SingleTopActivity,即会调用SingleTopActivity的onNewIntent方法。这就是上述日志的全过程。
#### **对以上内容进行总结**
standard启动模式是默认的启动模式,每次启动一个Activity都会新建一个实例不管栈中是否已有该Activity的实例。
#### **singleTop模式分3种情况**
1)当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法
2)当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例
3)当前栈中不存在该Activity的实例时,其行为同standard启动模式standard和singleTop启动模式都是在原任务栈中新建Activity实例,不会启动新的Task
### **singleTask模式**
在这个模式下,如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈,并且会回调该实例的onNewIntent方法。
#### **配置形式:**
```xml
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask"/>
<activity android:name=".OtherTaskActivity" android:launchMode="singleTask"/>
```
#### **使用案例:**
```java
public class SingleTaskActivity extends BaseActivity {
private Button jump,jump2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_task);
jump = (Button) findViewById(R.id.btn_task);
jump2 = (Button) findViewById(R.id.btn_other);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SingleTaskActivity.this, SingleTaskActivity.class);
startActivity(intent);
}
});
jump2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SingleTaskActivity.this, OtherTaskActivity.class);
startActivity(intent);
}
});
}}
```
```java
public class OtherTaskActivity extends BaseActivity {
private Button jump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other_task);
jump= (Button) findViewById(R.id.btn_other);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(OtherTaskActivity.this, SingleTaskActivity.class);
startActivity(intent);
}
});
}
}
```
#### **日志输出**
```
onCreate:MainActivity TaskId: 5 hasCode:1249321980
onCreate:SingleTaskActivity TaskId: 5 hasCode:1249515136
onCreate:OtherTaskActivity TaskId: 6 hasCode:1249386172
onNewIntent:SingleTaskActivity TaskId: 6 hasCode:1249513244
```
#### **测试结果:**
1)从MainActiviyty进入到SingleTaskActivity,再进入到OtherActivity后,此时栈中有3个Activity实例,并且SingleTaskActivity不在栈顶。
2)而在OtherActivity跳到SingleTaskActivity时,并没有创建一个新的SingleTaskActivity,而是复用了该实例,并且回调了onNewIntent方法。并且原来的OtherActivity出栈了,具体见下面的信息,使用命令adb shell dumpsys activity activities可进行查看
```
Running activities (most recent first):
TaskRecord{3c727e #11 A=com.maweiqi.task U=0 sz=2}
Run #1: ActivityRecord{5a00d1e u0 com.maweiqi.task/.SingleTaskActivity t11}
Run #0: ActivityRecord{2dce0b u0 com.maweiqi.task/.MainActivity t11}
```
可以看到当前栈中只有两个Activity,即原来栈中位于SingleTaskActivity 之上的Activity都出栈了。
### **singleInstance-全局唯一模式**
该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
#### **singleInstance示例一配置形式:**
```xml
<activity android:name=".MainActivity" android:launchMode="standard">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance"/>
```
```java
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_standard= (Button) findViewById(R.id.btn_standard);
btn_standard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SingleInstanceActivity.class);
startActivity(intent);
}
});
}
}
```
```java
public class SingleInstanceActivity extends BaseActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_instance);
Button button4 = (Button) findViewById(R.id.button4);
button4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SingleInstanceActivity.this, MainActivity.class);
startActivity(intent);
}
});
}
}
```
#### **测试方式:**
MainActivity--> SingleInstanceActivity--> MainActivity--> SingleInstanceActivity
#### **日志输出**
```
onCreate:MainActivity TaskId: 12 hasCode:201331476
onCreate:SingleInstanceActivity TaskId: 13 hasCode:57987178
onCreate:MainActivity TaskId: 12 hasCode:254253633
onNewIntent:SingleInstanceActivity TaskId: 13 hasCode:57987178
```
#### **测试结果**
1)两个SingleInstanceActivity是同一个实例。
2) 第一次进入的MainActivity和第一次进入的SingleInstanceActivity位于不同的task中。
3) 两个MainActivity是位于同一个task中的不同实例。
4)这个结论与预期是相同的,即,singleInstance类型的Activity的实例只能有一个,而且它只允许存在于单独的一个task中。
5)至于为什么两个MainActivity是位于同一个task中的不同实例,那是因为它是standard类型的,我们可以将ActivityTest修改为singleTop等其他类型进行测试。
#### **singleInstance示例二配置形式:**
MainActivity的模式改为"singleTop",修改后的manifest如下:
```xml
<activity android:name=".MainActivity" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance"/>
```
MainActivity进入SingleInstanceActivity,在从SingleInstanceActivity 进入MainActivity,在从MainActivity进入SingleInstanceActivity
#### **日志输出**
```
onCreate:MainActivity TaskId: 15 hasCode:201331476
onCreate:SingleInstanceActivity TaskId: 16 hasCode:57987178
onNewIntent:MainActivity TaskId: 15 hasCode:201331476
onNewIntent:SingleInstanceActivity TaskId: 16 hasCode:57987178
```
#### **测试结果**
1)两个SingleInstanceActivity是同一个实例。
2)第一次进入的MainActivity和第一次进入的SingleInstanceActivity位于不同的task中。
3)两个MainActivity是同一个实例。
### **launchMode模式总结**
#### **1. standard**
在该模式下,Activity可以拥有多个实例,并且这些实例既可以位于同一个task,也可以位于不同的task。
#### **2.singleTop**
该模式下,在同一个task中,如果存在该Activity的实例,并且该Activity实例位于栈顶(即,该Activity位于前端),则调用startActivity()时,不再创建该Activity的示例;而仅仅只是调用Activity的onNewIntent()。否则的话,则新建该Activity的实例,并将其置于栈顶。
#### **3. singleTask**
只容许有一个包含该Activity实例的task存在!
总的来说:singleTask的结论与android:taskAffinity相关(下章在讲),以A启动B来说
1) 当A和B的taskAffinity相同时:第一次创建B的实例时,并不会启动新的task,而是直接将B添加到A所在的task;否则,将B所在task中位于B之上的全部Activity都删除,然后跳转到B中。
2) 当A和B的taskAffinity不同时:第一次创建B的实例时,会启动新的task,然后将B添加到新建的task中;否则,将B所在task中位于B之上的全部Activity都删除,然后跳转到B中。
#### **4. singleInstance**
顾名思义,是单一实例的意思,即任意时刻只允许存在唯一的Activity实例,而且该Activity所在的task不能容纳除该Activity之外的其他Activity实例!
它与singleTask有相同之处,也有不同之处。
相同之处:任意时刻,最多只允许存在一个实例。
不同之处:
1) singleTask受android:taskAffinity属性的影响,而singleInstance不受android:taskAffinity的影响。
2) singleTask所在的task中能有其它的Activity,而singleInstance的task中不能有其他Activity。
3) 当跳转到singleTask类型的Activity,并且该Activity实例已经存在时,会删除该Activity所在task中位于该Activity之上的全部Activity实例;而跳转到singleInstance类型的Activity,并且该Activity已经存在时,不需要删除其他Activity,因为它所在的task只有该Activity唯一一个Activity实例。
参考链接:[http://blog.csdn.net/sbsujjbcy/article/details/49360615](http://blog.csdn.net/sbsujjbcy/article/details/49360615)
- 欢迎关注微信公众号,长期推荐技术文章和技术视频
- 微信公众号名称:Android干货程序员

================================================
FILE: docs/android/Android-Interview/Activity/深刻剖析activity启动模式-2.md
================================================
### 源码分析相关面试题
- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)
- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)
- [okhttp3.0源码分析](http://www.jianshu.com/p/9ed2c2f2a52c)
- [onSaveInstanceState源码分析](http://www.jianshu.com/p/cbf9c3557d64)
- [静默安装和源码编译](http://www.jianshu.com/p/2211a5b3c37f)
### Activity相关面试题
- [保存Activity的状态](http://www.jianshu.com/p/cbf9c3557d64)
- [深刻剖析activity启动模式(一)](http://www.jianshu.com/p/b33fd8c550bf)
- [深刻剖析activity启动模式(二)](http://www.jianshu.com/p/e1ea9e542112)
### 与XMPP相关面试题
- [XMPP协议优缺点](http://www.jianshu.com/p/2c04ac3c526a)
- [极光消息推送原理](http://www.jianshu.com/p/d88dc66908cf)
### 与性能优化相关面试题
- [内存泄漏和内存溢出区别](http://www.jianshu.com/p/5dd645b05c76)
- [UI优化和线程池实现原理](http://www.jianshu.com/p/c22398f8587f)
- [代码优化](http://www.jianshu.com/p/ebd41eab90df)
- [内存性能分析](http://www.jianshu.com/p/2665c31b9c2f)
- [内存泄漏检测](http://www.jianshu.com/p/1514c7804a06)
- [App启动优化](http://www.jianshu.com/p/f0f73fefdd43)
- [与IPC机制相关面试题](http://www.jianshu.com/p/de4793a4c2d0)
### 与登录相关面试题
- [oauth认证协议原理](http://www.jianshu.com/p/2a6ecbf8d49d)
- [token产生的意义](http://www.jianshu.com/p/9b7ce2d6c195)
- [微信扫一扫实现原理](http://www.jianshu.com/p/a9d1f21bd5e0)
### 与开发相关面试题
- [迭代开发的时候如何向前兼容新旧接口](http://www.jianshu.com/p/cbecadec98de)
- [手把手教你如何解决as jar包冲突](http://www.jianshu.com/p/30fdc391289c)
- [context的原理分析](http://www.jianshu.com/p/2706c13a1769)
- [解决ViewPager.setCurrentItem中间很多页面切换方案](http://www.jianshu.com/p/38ab6d856b56)
### 与人事相关面试题
- [人事面试宝典](http://www.jianshu.com/p/d61b553ff8c9)
### **实例验证singleTask启动模式**
上篇文章将activity的四种启动模式就基本介绍完了。为了加深对启动模式的了解,下面会通过一个简单的例子进行验证。由以上的介绍可知,standard和singleTop这两种启动模式行为比较简单,所以在下面的例子中,通过taskAffinity会对singleTask和singleInstance着重介绍。
#### **验证启动singleTask模式的activity时是否会创建新的任务**
这个实例中有三个Activity,分别为:MainActivity,SecondActivity和ThirdActivity。
#### **配置形式:**
```xml
<activity android:label="@string/app_name"
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:launchMode="singleTask">
<intent-filter >
<action android:name="com.maweiqi.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".ThirdActivity"
android:label="@string/app_name" >
</activity>
```
#### **说明:**
MainActivity和ThirdActivity都是标准的启动模式,而SecondActivity的启动模式为singleTask。
#### **使用案例:**
```java
public class MainActivity extends AppCompatActivity {
private static final String ACTIVITY_NAME = "MainActivity";
private static final String LOG_TAG = "maweiqi";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
int taskId = getTaskId();
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
```java
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intent);
}
});
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: "
+ getTaskId() + " hasCode:" + this.hashCode());
}
}
```
```java
public class ThirdActivity extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
#### **测试方式:**
MainActivity -->SecondActivity -->ThirdActivity。
#### **输出的日志如下:**
```
onCreate:MainActivity TaskId: 21 hasCode:199785693
onCreate:SecondActivity TaskId: 21 hasCode:171956091
```
#### **在命令行中执行以下命令 adb shell dumpsys activity ,有以下输出:**
```
Running activities (most recent first):
TaskRecord{838c0b8 #21 A=com.open.android.task1 U=0 sz=2}
Run #1: ActivityRecord{abf1b0a u0 com.open.android.task1/.SecondActivity t21}
Run #0: ActivityRecord{4e579b u0 com.open.android.task1/.MainActivity t21}
```
#### **测试结果:**
1)MainActivity和SecondActivity是启动在同一个任务中
2)在SecondActivity增加一个taskAffinity属性,如下所示:
```xml
<activity android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="com.maweiqi.second">
<intent-filter >
<action android:name="com.maweiqi.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
```
#### **测试方式:**
MainActivity -->SecondActivity -->ThirdActivity。
#### **输出的日志如下:**
```
onCreate:MainActivity TaskId: 24 hasCode:199785693
onCreate:SecondActivity TaskId: 25 hasCode:171956091
onCreate:ThirdActivity TaskId: 25 hasCode:76684615
```
#### **在命令行中执行以下命令 adb shell dumpsys activity ,有以下输出:**
```
Running activities (most recent first):
TaskRecord{844539b #25 A=com.maweiqi.second U=0 sz=2}
Run #2: ActivityRecord{2eb5348 u0 com.open.android.task1/.ThirdActivity t25}
Run #1: ActivityRecord{119f0df u0 com.open.android.task1/.SecondActivity t25}
TaskRecord{b730338 #24 A=com.open.android.task1 U=0 sz=1}
Run #0: ActivityRecord{2e05e2a u0 com.open.android.task1/.MainActivity t24}
```
#### **测试结果:**
1)MainActivity和SecondActivity运行在不同的任务中了
2)ThirdActivity和SecondActivity运行在同一个任务中
在这里便引出了manifest文件中<activity>的一个重要属性,taskAffinity。在官方文档中可以得到关于taskAffinity的以下信息
#### **taskAffinity**
1)taskAffinity表示当前activity具有亲和力的一个任务(翻译不是很准确,原句为The task that the activity has an affinity for.),大致可以这样理解,这个 taskAffinity表示一个任务,这个任务就是当前activity所在的任务。
2)在概念上,具有相同的affinity的activity(即设置了相同taskAffinity属性的activity)属于同一个任务。
3) 一个任务的affinity决定于这个任务的根activity(root activity)的taskAffinity。
4) 默认情况下,一个应用中的所有activity具有相同的taskAffinity,即应用程序的包名。我们可以通过设置不同的taskAffinity属性给应用中的activity分组,也可以把不同的 应用中的activity的taskAffinity设置成相同的值。
5)为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task。
#### **结果分析:**
1)这就可以解释上面示例中的现象了,由第4条可知,MainActivity和SecondActivity具有不同的taskAffinity,MainActivity的taskAffinity为com.open.android.task1,SecondActivity的taskAffinity为com.maweiqi.second。
2)当新启动的activity(SecondActivity)是以FLAG_ACTIVITY_NEW_TASK标志启动时(只有singleTask模式才会保证“single in task”,只使用FLAG_ACTIVITY_NEW_TASK并不保证“single in task”,或者说singleTask包含了FLAG_ACTIVITY_NEW_TASK,反之却不成立),framework会检索是否已经存在了一个affinity为com.maweiqi.second的任务(即一个TaskRecord对象)
3)如果存在这样的一个任务,则检查在这个任务中是否已经有了一个SecondActivity的实例。
3-1)如果已经存在一个SecondActivity的实例,则会重用这个任务和任务中的SecondActivity实例,将这个任务调到前台,清除位于SecondActivity上面的所有Activity,显示SecondActivity,并调用SecondActivity的onNewIntent();
3-2)如果不存在一个SecondActivity的实例,会在这个任务中创建SecondActivity的实例,并调用onCreate()方法
3-3)这是在设置了singleTask模式的情况下会这样,在没有设置singleTask模式的情况下(即默认的standard模式)使用FLAG_ACTIVITY_NEW_TASK,并不会清除位于SecondActivity上面的所有Activity,而是会在task的上面重新创建一个SecondActivity。也就是说此时task中有两个SecondActivity。
4)如果不存在这样的一个任务,会创建一个新的affinity为com.maweiqi.second的任务,并且将SecondActivity启动到这个新的任务中
上面讨论的是设置taskAffinity属性的情况,如果SecondActivity只设置启动模式为singleTask,而不设置taskAffinity,即三个Activity的taskAffinity相同,都为应用的包名,那么SecondActivity是不会开启一个新任务的,framework中的判定过程如下:
1)在MainActivity启动SecondActivity时,发现启动模式为singleTask,那么设定他的启动标志为FLAG_ACTIVITY_NEW_TASK
2)然后获得SecondActivity的taskAffinity,即为包名com.open.android.task1检查是否已经存在一个affinity为com.open.android.task1的任务,这个任务是存在的,就是MainActivity所在的任务,这个任务是在启动MainActivity时开启的
3)既然已经存在这个任务,就检索在这个任务中是否存在一个SecondActivity的实例,发现不存在在这个已有的任务中启动一个SecondActivity的实例
为了作一个清楚的比较,列出SecondActivity启动模式设为singleTask,并且taskAffinity设为com.maweiqi.second时的启动过程
1)在MainActivity启动SecondActivity时,发现启动模式为singleTask,那么设定他的启动标志为FLAG_ACTIVITY_NEW_TASK
2)然后获得SecondActivity的taskAffinity,即com.maweiqi.second检查是否已经存在一个affinity为com.maweiqi.second的任务,这个任务是不存在的创建一个新的affinity为com.maweiqi.second的任务,并且将SecondActivity启动到这个新的任务中
framework中对任务和activity的调度是很复杂的,尤其是把启动模式设为singleTask或者以FLAG_ACTIVITY_NEW_TASK标志启动时.所以,在使用singleTask和FLAG_ACTIVITY_NEW_TASK时,要仔细测试应用程序.
#### **实例验证将两个不同app中的不同的singleTask模式的Activity的taskAffinity设成相同**
官方文档中提到,可以把不同的 应用中的activity的taskAffinity设置成相同的值,这样的话这两个activity虽然不在同一应用中,却会在运行时分配到同一任务中,下面对此进行验证,在这里,会使用上面的示例,并创建一个新的示例AndroidTaskTest3。AndroidTaskTest3由两个activity组成,分别为MianActivity和OtherActivity,在MianActivity中点击按钮会启动OtherActivity,两个应用代码和布局一样,仅列出清单文件,两份清单文件如下:
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.open.android.task1">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="com.maweiqi.second">
<intent-filter >
<action android:name="com.maweiqi.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".ThirdActivity"/>
</application>
</manifest>
```
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.open.android.task3">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".OtherActivity"
android:taskAffinity="com.maweiqi.second"
android:launchMode="singleTask">
</activity>
</application>
</manifest>
```
可以看到OtherActivity和SecondActivity的启动模式都被设置为singleTask,并且taskAffinity属性被设置为com.maweiqi.second.现在将这两个应用安装在设备上。执行以下操作:
#### **测试方式:**
1)MainActivity --> SecondActivity
2)MainActivity --> OtherActivity
启动AndroidTaskTest应用,在它的MianActivity中点击按钮开启SecondActivity,由上面的介绍可知secondActivity是运行在一个新任务中的,这个任务就是com.maweiqi.second。
然后按Home键回到Launcher,启动AndroidTaskTest3,在启动AndroidTaskTest3的入口MianActivity时,会自动启动新的任务,那么现在一共有三个任务,AndroidTaskTest的MianActivity和SecondActivity分别占用一个任务,AndroidTaskTest3的MianActivity也占用一个任务。
在AndroidTaskTest3的MianActivity中点击按钮启动OtherActivity,那么这个OtherActivity是在哪个任务中呢?
#### **日志输出**
```
***AndroidTaskTest应用测试日志输出***
onCreate:MainActivity TaskId: 29 hasCode:193251508
onCreate:SecondActivity TaskId: 30 hasCode:171956091
***AndroidTaskTest3应用测试日志输出***
onCreate:MainActivity TaskId: 31 hasCode:199785693
onCreate:OtherActivity TaskId: 30 hasCode:171956091
```
下面执行adb shell dumpsys activity命令,发现有以下输出:
```
Task id #30
TaskRecord{7f2f34a #30 A=com.maweiqi.second U=0 sz=2}
Intent { flg=0x10000000 cmp=com.open.android.task1/.SecondActivity }
Hist #1: ActivityRecord{a0f9ded u0 com.open.android.task3/.OtherActivity t30}
Intent { flg=0x10400000 cmp=com.open.android.task3/.OtherActivity }
ProcessRecord{12090b5 27543:com.open.android.task3/u0a62}
Hist #0: ActivityRecord{1048af6 u0 com.open.android.task1/.SecondActivity t30}
Intent { flg=0x10000000 cmp=com.open.android.task1/.SecondActivity }
ProcessRecord{5bc013e 26035:com.open.android.task1/u0a59}
Task id #31
TaskRecord{dce52bb #31 A=com.open.android.task3 U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task3/.MainActivity }
Hist #0: ActivityRecord{f9e58c5 u0 com.open.android.task3/.MainActivity t31}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task3/.MainActivity }
ProcessRecord{12090b5 27543:com.open.android.task3/u0a62}
Task id #29
TaskRecord{5b063d8 #29 A=com.open.android.task1 U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task1/.MainActivity }
Hist #0: ActivityRecord{689947d u0 com.open.android.task1/.MainActivity t29}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.open.android.task1/.MainActivity }
ProcessRecord{5bc013e 26035:com.open.android.task1/u0a59}
Running activities (most recent first):
TaskRecord{7f2f34a #30 A=com.maweiqi.second U=0 sz=2}
Run #3: ActivityRecord{a0f9ded u0 com.open.android.task3/.OtherActivity t30}
TaskRecord{dce52bb #31 A=com.open.android.task3 U=0 sz=1}
Run #2: ActivityRecord{f9e58c5 u0 com.open.android.task3/.MainActivity t31}
TaskRecord{7f2f34a #30 A=com.maweiqi.second U=0 sz=2}
Run #1: ActivityRecord{1048af6 u0 com.open.android.task1/.SecondActivity t30}
TaskRecord{5b063d8 #29 A=com.open.android.task1 U=0 sz=1}
Run #0: ActivityRecord{689947d u0 com.open.android.task1/.MainActivity t29}
mResumedActivity: ActivityRecord{a0f9ded u0 com.open.android.task3/.OtherActivity t30}
```
#### **结果分析**
1)所以由此可见,AndroidTaskTest1的SecondActivity和AndroidTaskTest3的OtherActivity是在同一任务中的
2)由上面adb shell dumpsys activity命令的输出结果还可以看出,AndroidTaskTest1和AndroidTaskTest3这两个应用程序会开启两个进程,他们的所有组件分别运行在独立的进程中
3)AndroidTaskTest1所在进程的进程号为u0a59,AndroidTaskTest3所在进程的进程号为u0a62
4)com.maweiqi.second任务中的两个activity属于不同的应用,并且运行在不同的进程中,这也说明了一个问题:任务(Task)不仅可以跨应用(Application),还可以跨进程(Process)。
#### **实例验证singleTask的另一意义:在同一个任务中具有唯一性**
singleTask模式只意味着“可以在一个新的任务中开启”,至于是不是真的会在新任务中开启,在framework中还有其他条件的限制。由上面的介绍可知,这个条件为:是否已经存在了一个由他的taskAffinity属性指定的任务。这一点具有迷惑性,我们在看到singleTask这个单词的时候,会直观的想到它的本意:single in task。即,在同一个任务中,只会有一个该activity的实例。现在让我们进行验证:
为了验证这种情况,需要修改一下上面用到的AndroidTaskTest1示例。增加一个FourthActivity,并且MianActivity,SecondActivity,ThirdActivity和FourthActivity这四个activity都不设置taskAffinity属性,并且将SecondActivity启动模式设为singleTask,这样这四个activity会在同一个任务中开启。代码和软件界面就不列出了,只列出清单文件。
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.open.android.task1">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:launchMode="singleTask"
>
</activity>
<activity android:name=".ThirdActivity"/>
<activity android:name=".FourthActivity"/>
</application>
</manifest>
```
#### **测试方式:**
MianActivity --> SecondActivity --> ThirdActivity --> FourthActivity
#### **日志输出**
```
onCreate:MainActivity TaskId: 34 hasCode:199785693
onCreate:SecondActivity TaskId: 34 hasCode:171956091
onCreate:ThirdActivity TaskId: 34 hasCode:240438941
onCreate:FourthActivity TaskId: 34 hasCode:168147209
```
由此可见这四个activity都是在同一个任务中的。再次执行adb shell dumpsys activity命令加以验证:
```
Running activities (most recent first):
TaskRecord{d114530 #34 A=com.open.android.task1 U=0 sz=4}
Run #3: ActivityRecord{edae6a3 u0 com.open.android.task1/.FourthActivity t34}
Run #2: ActivityRecord{f9339a5 u0 com.open.android.task1/.ThirdActivity t34}
Run #1: ActivityRecord{1a30096 u0 com.open.android.task1/.SecondActivity t34}
Run #0: ActivityRecord{7e96fa4 u0 com.open.android.task1/.MainActivity t34}
```
#### **测试结果:**
1)同样可以说明目前这四个activity都运行在affinity为com.open.android.task1的任务中,即栈中的状态为MainActivity --> SecondActivity --> ThirdActivity --> FourthActivity。
下面执行在FourthActivity中点击按钮启动SecondActivity的操作,注意,SecondActivity的启动模式为singleTask,那么现在栈中的情况如何呢?
#### **日志输出**
```
没有日志输出,说明没有调用onCreate方法
```
再次执行adb shell dumpsys activity命令,有以下输出:
```
Running activities (most recent first):
TaskRecord{d114530 #34 A=com.open.android.task1 U=0 sz=2}
Run #1: ActivityRecord{1a30096 u0 com.open.android.task1/.SecondActivity t34}
Run #0: ActivityRecord{7e96fa4 u0 com.open.android.task1/.MainActivity t34}
```
#### **测试结果:**
1)这时栈中的状态为MainActivity --> SecondActivity。确实确保了在任务中是唯一的,并且清除了同一任务中它上面的所有Activity。
2)那么这个SecondActivity的实例是重用的上次已有的实例还是重新启动了一个实例呢?可以观察系统Log, 发现系统Log没有改变,还是上面的四条Log。打印Log的语句是在各个Activity中的onCreate方法中执行的,没有打印出新的Log,说明SecondActivity的onCreate的方法没有重新执行,也就是说是重用的上次已经启动的实例,而不是销毁重建。
#### **结果分析:**
1)经过上面的验证,可以得出如下的结论:在启动一个singleTask的Activity实例时,如果系统中已经存在这样一个实例,就会将这个实例调度到任务栈的栈顶,并清除它当前所在任务中位于它上面的所有的activity。
### **实例验证singleInstance的行为**
考谷歌官方文档,singleInstance的特点可以归结为以下三条:
1)以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例
2)以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中(官方文档上的描述为,singleInstance模式的Activity不允许其他Activity和它共存在一个任务中)
3)被singleInstance模式的Activity开启的其他activity,能够开启一个新任务,但不一定开启新的任务,也可能在已有的一个任务中开启
下面对这三个特点分别验证,所使用的示例同样为AndroidTaskTest1,只不过会进行一些修改,下面列出它的清单文件:
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.open.android.task1">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:launchMode="singleInstance"
>
<intent-filter>
<action android:name="com.maweiqi.ACTION_MY"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".ThirdActivity"/>
<activity android:name=".FourthActivity"/>
</application>
</manifest>
```
由上面的清单文件可以知道,该应用包括四个activity,分别为MianActivity,SecondActivity,ThirdActivity,FourthActivity,其中SecondActivity启动模式设置为singleInstance。MianActivity可以开启SecondActivity,SecondActivity可以开启ThirdActivity。 并且为了可以在其他应用中开启SecondActivity,为SecondActivity设置了一个IntentFilter,这样就可以在其他应用中使用隐式Intent开启SecondActivity。
#### **测试方式:**
MianActivity --> SecondActivity --> ThirdActivity
为了更好的验证singleInstance的全局唯一性,还需要其他一个应用,新建AndroidTaskTest4。AndroidTaskTest4只需要一个MianActivity,在MainActivity中点击按钮会开启AndroidTaskTest1应用中的SecondActivity。开启AndroidTaskTest1应用中的SecondActivity的代码如下:
```java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("com.maweiqi.ACTION_MY");
startActivity(intent);
}
});
}
}
```
#### **下面开始验证第一个特点:以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例**
执行如下操作:安装AndroidTaskTest1应用,点击MainActivity中的按钮,开启SecondActivity,可以看到如下log输出:
#### **日志输出**
```
onCreate:MainActivity TaskId: 35 hasCode:199785693
onCreate:SecondActivity TaskId: 36 hasCode:171956091
```
执行adb shell dumpsys activity命令,有以下输出:
```
Running activities (most recent first):
TaskRecord{2b68544 #36 A=com.open.android.task1 U=0 sz=1}
Run #1: ActivityRecord{6d9f8c u0 com.open.android.task1/.SecondActivity t36}
TaskRecord{ae9a62d #35 A=com.open.android.task1 U=0 sz=1}
Run #0: ActivityRecord{d0429f5 u0 com.open.android.task1/.MainActivity t35}
```
以上可以说明,singleInstance模式的Activity总是会在新的任务中运行(前提是系统中还不存在这样的一个实例) 。
下面验证它的全局唯一性,执行以下操作:安装另一个应用AndroidTaskTest4,在开启的MainActivity中点击按钮开启AndroidTaskTest1应用中的SecondActivity。看到打印出一条新的日志:
```
{act=com.maweiqi.ACTION_MY cmp=com.open.android.task1/.SecondActivity} from uid 10063 on display 0
```
执行adb shell dumpsys activity命令,有以下输出:
```
Running activities (most recent first):
TaskRecord{2b68544 #36 A=com.open.android.task1 U=0 sz=1}
Run #2: ActivityRecord{6d9f8c u0 com.open.android.task1/.SecondActivity t36}
TaskRecord{a7e9abd #37 A=com.open.android.task4 U=0 sz=1}
Run #1: ActivityRecord{f50eec0 u0 com.open.android.task4/.MainActivity t37}
TaskRecord{ae9a62d #35 A=com.open.android.task1 U=0 sz=1}
Run #0: ActivityRecord{d0429f5 u0 com.open.android.task1/.MainActivity t35}
```
#### **测试结果:**
1)开启的SecondActivity就是上次创建的编号为6d9f8c的SecondActivity。
2)Log中没有再次输出关于SecondActivity的信息,说明SecondActivity并没有重新创建
#### **结果分析:**
以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
#### **下面开始验证第二个特点:以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中**
重新安装AndroidTaskTest1应用,点击MainActivity中的按钮,开启SecondActivity,在SecondActivity中点击按钮,开启ThirdActivity。可以看到有如下Log输出:
#### **测试方式:**
MainActivity --> SecondActivity --> ThirdActivity
#### **日志输出:**
```
onCreate:MainActivity TaskId: 42 hasCode:199785693
onCreate:SecondActivity TaskId: 43 hasCode:171956091
onCreate:ThirdActivity TaskId: 42 hasCode:76684615
```
执行adb shell dumpsys activity命令,有以下输出:
```
Running activities (most recent first):
TaskRecord{ace0710 #42 A=com.open.android.task1 U=0 sz=2}
Run #3: ActivityRecord{322319f u0 com.open.android.task1/.ThirdActivity t42}
TaskRecord{abc9c0e #43 A=com.open.android.task1 U=0 sz=1}
Run #2: ActivityRecord{903a842 u0 com.open.android.task1/.SecondActivity t43}
TaskRecord{ace0710 #42 A=com.open.android.task1 U=0 sz=2}
Run #1: ActivityRecord{e3c0ddf u0 com.open.android.task1/.MainActivity t42}
```
#### **测试结果:**
SecondActivity所在的任务为43,被SecondActivity启动的ThirdActivity所在的任务为42,这就说明以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中
#### **下面开始验证第三个特点:被singleInstance模式的Activity开启的其他activity,能够在新的任务中启动,但不一定开启新的任务,也可能在已有的一个任务中开启**
有上面对第二个特点的验证可以看到,被SecondActivity启动的ThirdActivity并没有运行在一个新开启的任务中,而是和MainActivity运行在了同一个已有的任务中,那么在什么情况下ThirdActivity才会启动一个新的任务呢?
现在对程序的清单文件做以下修改,为ThirdActivity增加一个属性taskAffinity:
#### **配置如下:**
```
<activity android:name=".ThirdActivity"
android:taskAffinity="com.maweiqi.second"/>
```
重新安装AndroidTaskTest1应用,执行和上一步中同样的操作:点击MainActivity中的按钮,开启SecondActivity,在SecondActivity中点击按钮,开启ThirdActivity。可以看到有如下输出:
```
onCreate:MainActivity TaskId: 44 hasCode:199785693
onCreate:SecondActivity TaskId: 45 hasCode:171956091
onCreate:ThirdActivity TaskId: 46 hasCode:76684615
```
执行adb shell dumpsys activity命令,有以下输出:
```
Running activities (most recent first):
TaskRecord{3088b56 #46 A=com.maweiqi.second U=0 sz=1}
Run #2: ActivityRecord{9eff1ed u0 com.open.android.task1/.ThirdActivity t46}
TaskRecord{f9bb7d7 #45 A=com.open.android.task1 U=0 sz=1}
Run #1: ActivityRecord{16c7b28 u0 com.open.android.task1/.SecondActivity t45}
TaskRecord{e9af8c4 #44 A=com.open.android.task1 U=0 sz=1}
Run #0: ActivityRecord{5c2ed47 u0 com.open.android.task1/.MainActivity t44}
```
#### **测试结果:**
1)被SecondActivity启动的ThirdActivity启动在了一个新的任务中,即在启动ThirdActivity时创建了一个新任务。这就说明被singleInstance模式的Activity A在开启另一activity B时,能够开启一个新任务,但是是不是真的开启新任务,还要受其他条件的限制,这个条件是:当前系统中是不是已经有了一个activity B的taskAffinity属性指定的任务。
其实这种行为和singleTask启动时的情况相同。在Activity的启动模式设置为singleTask时,启动时系统会为它加上FLAG_ACTIVITY_NEW_TASK标志,而被singleInstance模式的Activity开启的activity,启动时系统也会为它加上FLAG_ACTIVITY_NEW_TASK标志,所以他们启动时的情况是相同的,上面再验证singleTask时已经阐述过,现在重新说明一下:
#### **结果分析:**
由于ThirdActivity是被启动模式为singleInstance类型的Activity(即SecondActivity)启动的,framework会为它它加上FLAG_ACTIVITY_NEW_TASK标志,这时 framework会检索是否已经存在了一个affinity为com.maweiqi.second(即ThirdActivity的taskAffinity属性)的任务
1)如果存在这样的一个任务,则检查在这个任务中是否已经有了一个ThirdActivity的实例.
1-1)如果已经存在一个ThirdActivity的实例,则会重用这个任务和任务中的ThirdActivity实例,将这个任务调到前台,清除位于ThirdActivity上面的所有Activity,显示ThirdActivity,并调用ThirdActivity的onNewIntent()。
1-2)如果不存在一个ThirdActivity的实例,会在这个任务中创建ThirdActivity的实例,并调用onCreate()方法
1-3)需要注意(1-1)有一种特殊情况,MainActivity, SecondActivity, ThirdActivity, FourthActivity 都不设置 taskAffinity.FourthActivity 设置为 singleInstance。测试 MainActivity -> SecondActivity -> ThirdActivity -> FourthActivity -> SecondActivity,从 FourthActivity 跳转到 SecondActivity, 是新开的一个 SecondActivity, 不会销毁 原 SecondActivity 上面的 ThirdActivity。
2)如果不存在这样的一个任务,会创建一个新的affinity为com.maweiqi.second的任务,并且将ThirdActivity启动到这个新的任务中.
如果ThirdActivity不设置taskAffinity,即ThirdActivity和MainActivity的taskAffinity相同,都为应用的包名,那么ThirdActivity是不会开启一个新任务的.
#### **framework中的判定过程如下:**
1)在SecondActivity启动ThirdActivity时,因为SecondActivity是singleInstance的,所以设定ThirdActivity的启动标志为FLAG_ACTIVITY_NEW_TASK
2)然后获得ThirdActivity的taskAffinity,即为包名com.open.android.task1
3)检查是否已经存在一个affinity为com.open.android.task1的任务,这个任务是存在的,就是MainActivity所在的任务,这个任务是在启动MainActivity时开启的
4) 既然已经存在这个任务,就检索在这个任务中是否存在一个ThirdActivity的实例,发现不存在
5)在这个已有的任务中启动一个SecondActivity的实例
#### **为了作一个清楚的比较,列出ThirdActivity的taskAffinity属性设为com.maweiqi.second时的启动过程**
1)在SecondActivity启动ThirdActivity时,因为SecondActivity是singleInstance的,那么设定ThirdActivity的启动标志为FLAG_ACTIVITY_NEW_TASK
2)然后获得ThirdActivity的taskAffinity,即为com.maweiqi.second
3)检查是否已经存在一个affinity为com.maweiqi.second的任务,这个任务是不存在的
4) 创建一个新的affinity为com.maweiqi.second的任务,并且将ThirdActivity启动到这个新的任务
到此singleInstance也介绍完了。
### 小结
由上述可知,Task是Android Framework中的一个概念,Task是由一系列相关的Activity组成的,是一组相关Activity的集合。Task是以栈的形式来管理的。
我们在操作软件的过程中,一定会涉及界面的跳转。其实在对界面进行跳转时,Android Framework既能在同一个任务中对Activity进行调度,也能以Task为单位进行整体调度。在启动模式为standard或singleTop时,一般是在同一个任务中对Activity进行调度,而在启动模式为singleTask或singleInstance是,一般会对Task进行整体调度。
#### **对Task进行整体调度包括以下操作:**
1)按Home键,将之前的任务切换到后台
2)长按Home键,会显示出最近执行过的任务列表
3)在Launcher或HomeScreen点击app图标,开启一个新任务,或者是将已有的任务调度到前台
4)启动singleTask模式的Activity时,会在系统中搜寻是否已经存在一个合适的任务,若存在,则会将这个任务调度到前台以重用这个任务。如果这个任务中已经存在一个要启动的Activity的实例,则清除这个实例之上的所有Activity,将这个实例显示给用户。如果这个已存在的任务中不存在一个要启动的Activity的实例,则在这个任务的顶端启动一个实例。若这个任务不存在,则会启动一个新的任务,在这个新的任务中启动这个singleTask模式的Activity的一个实例。
5)启动singleInstance的Activity时,会在系统中搜寻是否已经存在一个这个Activity的实例,如果存在,会将这个实例所在的任务调度到前台,重用这个Activity的实例(该任务中只有这一个Activity),如果不存在,会开启一个新任务,并在这个新任务中启动这个singleInstance模式的Activity的一个实例。
================================================
FILE: docs/android/Android-Interview/Activity/深刻剖析activity启动模式-3.md
================================================
前面介绍了通过launchMode设置Activity的启动模式。本章接着介绍Activity的启动模式相关内容,讲解的内容是Intent与启动模式相关的Flag,以及android:taskAffinity的属性。
### **Intent与启动模式相关的Flag简介**
这里仅仅对几个常用的与启动模式相关的Flag进行介绍。
#### **FLAG_ACTIVITY_NEW_TASK**
很少单独使用FLAG_ACTIVITY_NEW_TASK,通常与FLAG_ACTIVITY_CLEAR_TASK或FLAG_ACTIVITY_CLEAR_TOP联合使用。因为单独使用该属性会导致奇怪的现象,通常达不到我们想要的效果!尽管如何,后面还是会通过"FLAG_ACTIVITY_NEW_TASK示例一"和"FLAG_ACTIVITY_NEW_TASK示例二"会向你展示单独使用它的效果。
#### **FLAG_ACTIVITY_SINGLE_TOP**
在google的官方文档中介绍,它与launchMode="singleTop"具有相同的行为。实际上,的确如此!单独的使用FLAG_ACTIVITY_SINGLE_TOP,就能达到和launchMode="singleTop"一样的效果。
#### **FLAG_ACTIVITY_CLEAR_TOP**
顾名思义,FLAG_ACTIVITY_CLEAR_TOP的作用清除"包含Activity的task"中位于该Activity实例之上的其他Activity实例。FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK两者同时使用,就能达到和launchMode="singleTask"一样的效果!
#### **FLAG_ACTIVITY_CLEAR_TASK**
FLAG_ACTIVITY_CLEAR_TASK的作用包含Activity的task。使用FLAG_ACTIVITY_CLEAR_TASK时,通常会包含FLAG_ACTIVITY_NEW_TASK。这样做的目的是启动Activity时,清除之前已经存在的Activity实例所在的task;这自然也就清除了之前存在的Activity实例!
注意:当同时使用launchMode和上面的FLAG_ACTIVITY_NEW_TASK等标签时,以FLAG_ACTIVITY_NEW_TASK为标准。也就是说,代码的优先级比manifest中配置文件的优先级更高!
下面,通过几个实例加深对这几个标记的理解。
#### **FLAG_ACTIVITY_NEW_TASK标签**
#### **配置形式:**
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.open.android.task5">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="SecondActivity" />
</application>
</manifest>
```
#### **说明:**
在该实例中,有两个MainActivity和SecondActivity。
#### **使用案例:**
```java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).
setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i("maweiqi", "onNewIntent:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
注意,跳转的Intent添加了FLAG_ACTIVITY_NEW_TASK标志。
```java
public class SecondActivity extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Button button = (Button) findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SecondActivity.this, MainActivity.class);
startActivity(intent);
}
});
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i("maweiqi", "onNewIntent:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
#### **测试方式:**
MainActivity--> SecondActivity --> MainActivity--> SecondActivity
#### **输出的日志如下:**
```
onCreate:MainActivity TaskId: 73 hasCode:195694529
onCreate:SecondActivity TaskId: 73 hasCode:54326677
onCreate:MainActivity TaskId: 73 hasCode:121740648
onCreate:SecondActivity TaskId: 73 hasCode:5761837
```
#### **在命令行中执行以下命令 adb shell dumpsys activity ,有以下输出:**
```
Running activities (most recent first):
TaskRecord{e3d17e2 #73 A=com.open.android.task5 U=0 sz=4}
Run #3: ActivityRecord{a34fa00 u0 com.open.android.task5/.SecondActivity t73}
Run #2: ActivityRecord{21172da u0 com.open.android.task5/.MainActivity t73}
Run #1: ActivityRecord{b1e1e64 u0 com.open.android.task5/.SecondActivity t73}
Run #0: ActivityRecord{f015a6e u0 com.open.android.task5/.MainActivity t73}
mResumedActivity: ActivityRecord{a34fa00 u0 com.open.android.task5/.SecondActivity t73}
```
#### **测试结果:**
1)全部在同一个task中
2)全部创建不同的实例
那如果MainActivity跳转去掉FLAG_ACTIVITY_NEW_TASK?在SecondActivity清单文件添加singleTask,代码和流程跟之前一样,只贴出清单文件配置
#### **配置如下:**
```xml
<activity android:name="SecondActivity"
android:launchMode="singleTask"/>
```
#### **测试方式:**
MainActivity--> SecondActivity --> MainActivity--> SecondActivity
#### **输出的日志如下:**
```
onCreate:MainActivity TaskId: 74 hasCode:195694529
onCreate:SecondActivity TaskId: 74 hasCode:54326677
onCreate:MainActivity TaskId: 74 hasCode:38155814
onNewIntent:SecondActivity TaskId: 74 hasCode:54326677
```
#### **在命令行中执行以下命令 adb shell dumpsys activity ,有以下输出:**
```
Running activities (most recent first):
TaskRecord{46d0de2 #74 A=com.open.android.task5 U=0 sz=2}
Run #1: ActivityRecord{b31602f u0 com.open.android.task5/.SecondActivity t74}
Run #0: ActivityRecord{f88d9dc u0 com.open.android.task5/.MainActivity t74}
mResumedActivity: ActivityRecord{b31602f u0 com.open.android.task5/.SecondActivity t74}
```
#### **测试结果:**
1)FLAG_ACTIVITY_NEW_TASK的作用和singleTask具有不同的效果
那如果两个Activity的android:taskAffinity不相同呢?此时会导致什么效果呢?下面,我们通过示例来看看效果。
#### **配置如下:**
```xml
<activity android:name="SecondActivity"
android:taskAffinity="com.maweiqi.second"/>
```
代码回到最初MainActivity还是添加Flag标记,其他省略,如下:
```java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).
setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i("maweiqi", "onNewIntent:" + getClass().getSimpleName() +
" TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
}
}
```
#### **测试方式:**
MainActivity--> SecondActivity --> MainActivity--> SecondActivity
#### **输出的日志如下:**
```
onCreate:MainActivity TaskId: 77 hasCode:195694529
onCreate:SecondActivity TaskId: 78 hasCode:54326677
onCreate:MainActivity TaskId: 78 hasCode:38155814
```
#### **在命令行中执行以下命令 adb shell dumpsys activity ,有以下输出:**
```
Running activities (most recent first):
TaskRecord{65dda1d #78 A=com.maweiqi.second U=0 sz=2}
Run #2: ActivityRecord{845c9ed u0 com.open.android.task5/.MainActivity t78}
Run #1: ActivityRecord{f813328 u0 com.open.android.task5/.SecondActivity t78}
TaskRecord{dd8e492 #77 A=com.open.android.task5 U=0 sz=1}
Run #0: ActivityRecord{7a85f99 u0 com.open.android.task5/.MainActivity t77}
mResumedActivity: ActivityRecord{845c9ed u0 com.open.android.task5/.MainActivity t78}
```
#### **测试结果:**
1)当第二次进入到MainActivity中,再企图从MainActivity中进入到SecondActivity时,没有产生任何效果,仍然停留在MainActivity中!即第二次MainActivity--> SecondActivity压根就没发生!
#### **结果分析:**
1)当相互跳转的两个Activity的android:taskAffinity不同时,添加FLAG_ACTIVITY_NEW_TASK:第一次启动SecondActivity时,会新建一个task,并将SecondActivity添加到该task中。这与singleTask产生的效果是一样的!但是,当企图再次从MainActivity进入到SecondActivity时,却什么也没有发生!
2)为什么呢?是因为此时SecondActivity实例已经存在,但是它所在的task的栈顶是MainActivity;而单独的添加FLAG_ACTIVITY_NEW_TASK又不会"删除task中位于SecondActivity之上的Activity实例",所以就没有发生跳转!
#### **FLAG_ACTIVITY_CLEAR_TOP。**
修改MainActivity里面的点击事件如下:
```java
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
```
```java
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="SecondActivity"/>
```
#### **测试方式:**
MainActivity--> SecondActivity --> MainActivity--> SecondActivity
#### **日志输出**
```
onCreate:MainActivity TaskId: 80 hasCode:58656936
onCreate:SecondActivity TaskId: 80 hasCode:212434303
onCreate:MainActivity TaskId: 80 hasCode:121740648
onCreate:SecondActivity TaskId: 80 hasCode:15009890
```
#### **测试结果:**
1) MainActivity和SecondActivity在同一个task中!
2) 两个SecondActivity是不同的实例。
#### **结果分析:**
这与没有添加FLAG_ACTIVITY_CLEAR_TOP时效果一样!这说明,当相互跳转的两个Activity的android:taskAffinity一样时,不会产生任何效果!
接下来,看看不同android:taskAffinity的情况,代码一致,清单文件修改
#### **文件配置**
```xml
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="SecondActivity"
android:taskAffinity="com.maweiqi.second"/>
```
#### **测试方式:**
MainActivity--> SecondActivity --> MainActivity--> SecondActivity
#### **日志输出**
```
onCreate:MainActivity TaskId: 83 hasCode:195694529
onCreate:SecondActivity TaskId: 84 hasCode:54326677
onCreate:MainActivity TaskId: 84 hasCode:190178689
onCreate:SecondActivity TaskId: 84 hasCode:5761837
```
#### **在命令行中执行以下命令 adb shell dumpsys activity ,有以下输出:**
```
Running activities (most recent first):
TaskRecord{12e942 #84 A=com.maweiqi.second U=0 sz=1}
Run #1: ActivityRecord{e0674b5 u0 com.open.android.task5/.SecondActivity t84}
TaskRecord{62b9d53 #83 A=com.open.android.task5 U=0 sz=1}
Run #0: ActivityRecord{71ec08a u0 com.open.android.task5/.MainActivity t83}
mResumedActivity: ActivityRecord{e0674b5 u0 com.open.android.task5/.SecondActivity t84}
```
#### **测试结果:**
1)MainActivity和SecondActivity在不同task中!
2) 两个SecondActivity是不同实例。
#### **结果分析:**
FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP的使用和android:taskAffinity相关。
在同时使用FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TOP的情况下,以A启动B来说
1)当A和B的taskAffinity相同时:添加FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TOP没有任何作用。和没有添加时的效果一样!
2)当A和B的taskAffinity不同时:添加FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TOP后,如果该activity没有设置启动模式(即默认是standard),或者intent没有设置一个FLAG_ACTIVITY_SINGLE_TOP 的flag,那么这个activity就会销毁,然后重新创建这个实例
### **总结:**
#### **Activity的启动模式**
在AndroidManifest.xml中,可以配置每个activity的启动模式:例如:
android:launchMode="standard"
#### **(1) standard 标准模式**
此模式,不管有没有已存在的实例,都生成新的实例。每次调用startActivity()启动Activity时都会创建一个新的Activity放在栈顶,每次返回都会销毁实例并出栈,可以重复创建。
#### **(2) singletop 单一顶部模式**
如果任务栈的栈顶存在这个要开启的activity,不会重新创建新的activity,而是复用已存在的activity。保证栈顶如果存在,则不会重复创建,但如果不在栈顶,那么还是会创建新的实例。
应用场景:浏览器的书签
#### **(3) singletask 单一任务模式**
是一个比较严格的模式,在当前任务栈里面只能有一个实例存在,当开启activity的时候,就去检查在任务栈里面是否有实例已经存在,如果有实例存在就复用这个已经存在的activity,并且把这个activity上面的所有的别的activity都清空,复用这个已经存在的activity。
应用场景:BrowserActivity 浏览器界面
如果一个activity的创建需要占用大量的系统资源(cpu,内存)一般配置这个activity为singletask的启动模式。webkit内核(c) 初始化需要大量内存 js解析引擎 html渲染引擎 http解析,下载…减少内存开销,cpu占用。播放器的播放Activity
#### **(4) singleInstance**
这种启动模式比较特殊,它会启用一个新的任务栈,activity会运行在自己的任务栈里,这个任务栈里面只有一个实例存在并且保证不再有其他Activity实例进入。在整个手机操作系统里面只有一个实例存在。
应用场景:来电页面。InCallScreenActivity
### **最后的总结:**
实话说,关于任务栈的bug有点多,如果真的添加了启动模式,一定要多多测试,有的地方和官方文档描述完全不相符。
stackoverflow上也有人吐糟。
[http://stackoverflow.com/questions/9772927/flag-activity-new-task-clarification-needed](http://stackoverflow.com/questions/9772927/flag-activity-new-task-clarification-needed)
================================================
FILE: docs/android/Android-Interview/Android/Android基础面试核心内容.md
================================================
## Android基本常识
### 1. 写10个简单的linux命令
| 命令 | 作用 |
| :------- | :--------------------- |
| mkdir | 创建文件夹 |
| rmdir | 删除文件夹 |
| mv | 移动文件 |
| rm | 删除文件 |
| cp | 拷贝文件 |
| cat | 查看文件 |
| tail | 查看文件尾部 |
| more | 分页查看文件 |
| cd | 切换当前目录 |
| ls | 列出文件清单 |
| reboot | 重启 |
| date | 显示日期 |
| cal | 显示日历 |
| ps | 查看系统进程相当于windows的任务管理器 |
| ifconfig | 配置网络 |
### 2. 书写出android工程的目录结构
```
│ build.gradle 项目Gradle构建脚本
│ gradle.properties 项目Gradle属性文件
│ gradlew 在没有安装gradle的pc上使用,没用
│ gradlew.bat 在没有安装gradle的pc上使用,没用
│ local.properties 指定sdk所在目录
│ settings.gradle 项目Gradle设置文件
│
├─.gradle
├─.idea
├─app
│ │ .gitignore git忽略文件列表
│ │ app.iml 临时文件,不需要关心
│ │ build.gradle Module Gradle构建脚本
│ │ proguard-rules.pro proguard混淆规则
│ │
│ ├─build 构建目录,相当于Eclipse中默认Java工程的bin目录。编译生成的apk在此目录
│ ├─libs 依赖包
│ └─src
│ ├─androidTest 测试相关代码文件夹
│ │ └─java
│ │ └─com
│ │ └─itheima
│ │ └─myapplication
│ │ ApplicationTest.java
│ │
│ └─main
│ │ AndroidManifest.xml 清单文件
│ │
│ ├─assets
│ ├─aidl
│ ├─java 项目源码
│ │ └─com
│ │ └─itheima
│ │ └─myapplication
│ │ MainActivity.java
│ │
│ ├─jni 放置c代码
│ ├─jniLibs 放置so库
│ ├─assets
│ └─res 资源文件
│ ├─drawable .9图片只能放到drawable目录下
│ ├─layout
│ │ activity_main.xml
│ │
│ ├─menu
│ │ menu_main.xml
│ │
│ ├─mipmap-hdpi 类似drawable-hdpi
│ │ ic_launcher.png
│ │
│ ├─mipmap-mdpi 类似drawable-mdpi
│ │ ic_launcher.png
│ │
│ ├─mipmap-xhdpi 类似drawable-xdpi
│ │ ic_launcher.png
│ │
│ ├─mipmap-xxhdpi 类似drawable-xxdpi
│ │ ic_launcher.png
│ │
│ ├─values
│ │ dimens.xml
│ │ strings.xml
│ │ styles.xml
│ │
│ └─values-w820dp
│ dimens.xml
│
├─build
└─gradle
└─wrapper gradle wrapper可以看作是对gradle的封装,它可以使得在没有安装gradle的电脑上也可以使用Gradle进行构建
gradle-wrapper.jar
gradle-wrapper.properties
```
### 3. 什么是ANR 如何避免它?
在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。不同的组件发生ANR的时间不一样,主线程(Activity、Service)是5秒,BroadCastReceiver是10秒。
解决方案:
将所有耗时操作,比如访问网络,Socket通信,查询大量SQL语句,复杂逻辑计算等都放在子线程中去,然后通过handler.sendMessage()、runonUITread()、AsyncTask等方式更新UI。无论如何都要确保用户界面操作的流畅度。如果耗时操作需要让用户等待,那么可以在界面上显示进度条。
### 4. 谈谈Android的优点和不足之处
优点:
- 开放性,开源,免费,可定制
- 挣脱运营商束缚
- 丰富的硬件选择
- 不受任何限制的开发商
- 无缝结合的Google应用
缺点:
- 安全问题、隐私问题
- 同质化严重
- 运营商对Android手机仍然有影响
- 山寨化严重
- 过分依赖开发商,缺乏标准配置
### 5.一条最长的短信息约占多少byte?
在国内的三大运营商通常情况下中文70(包括标点),英文160个。对于国外的其他运行商具体多长需要看运营商类型了。
android内部是通过如下代码进行判断具体一个短信多少byte的。
ArrayList<String> android.telephony.SmsManager.divideMessage(String text)
### 6. sim卡的EF文件有何作用?
基本文件EF(Elementary File)是SIM卡文件系统的一部分。
| 文件 | 文件标识符 | 文件缩写 | 中文名称 | 文件作用 |
| --------------- | ----- | ------- | ---------------------------------------- | ---------------------------------------- |
| MF | 3F00 | 根目录 | 备注:所有非ETSI GSM协议中规定的应用文件由各厂家自行定义在根目录下(如:PIN1,PIN2…) | |
| EFICCID | 2FE2 | ICCID | SIM卡唯一的识别号 | 包含运营商、卡商、发卡时间、省市代码等信息 |
| DFGSM | 7F20 | GSM目录 | 备注:根据ETSIGSM09.91的规定Phase2(或以上)的SIM卡中应该有7F21并指向7F20,用以兼容Phase1的手机 | |
| EFLP语言选择 | 6F05 | LP | 语言选择文件 | 包含一种或多种语言编码 |
| EFIMSI | 6F07 | IMSI | 国际移动用户识别符 | 包含SIM卡所对应的号段,比如46000代表135-139号段、46002代表1340-1348 |
| EFKC语音加密密钥 | 6F20 | Kc | 计算密钥 | 用于SIM卡的加密、解密 |
| EFPLMNsel网络选择表 | 6F30 | PLMNsel | 公共陆地网选择 | 决定SIM卡选择哪种网络,在这里应该选择中国移动的网络 |
| EFHPLMN归属地网络选择表 | 6F31 | HPLMN | 两次搜索PLMN的时间间隔 | 两次搜索中国移动的网络的时间间隔 |
| EFACMmax最大计费额 | 6F37 | ACMmax | 包含累积呼叫表的最大值 | 全部的ACM数据存在SIM卡中,此处取最大值 |
| EFSST SIM卡服务表 | 6F38 | SST | SIM卡服务列表 | 指出SIM卡可以提供服务的种类,哪些业务被激活哪些业务没有开通 |
| EFACM累加计费计数器 | 6F39 | ACM | 累计呼叫列表 | 当前的呼叫和以前的呼叫的单位总和 |
| EFGID1分组识别1 | 6F3E | GID1 | 1级分组识别文件 | 包含特定的SIM-ME组合的标识符,可以识别一组特定的SIM卡 |
| EFGID2分组识别2 | 6F3F | GID2 | 2级分组识别文件 | 包含特定的SIM-ME组合的标识符,可以识别一组特定的SIM卡 |
| EFPUCT单位价格/货币表 | 6F41 | PUCT | 呼叫单位的价格和货币表 | PUCT是与计费通知有关的信息,ME用这个信息结合EFACM,以用户选择的货币来计算呼叫费用 |
| EFCBMI小区广播识别号 | 6F45 | CBMI | 小区广播信息标识符 | 规定了用户希望MS采纳的小区广播消息内容的类型 |
| EFSPN服务提供商 | 6F46 | SPN | 服务提供商名称 | 包含服务提供商的名称和ME显示的相应要求 |
| EFCBMID | 6F48 | CBMID | 数据下载的小区广播消息识别符 | 移动台将收到的CBMID传送给SIM卡 |
| EFSUME | 6F54 | SUME | 建立菜单单元 | 建立SIM卡中的菜单 |
| EFBCCH广播信道 | 6F74 | BCCH | 广播控制信道 | 由于BCCH的存储,在选择小区时,MS可以缩小对BCCH载波的搜索范围 |
| EFACC访问控制级别 | 6F78 | ACC | 访问控制级别 | SIM卡有15个级别,10个普通级别,5个高级级别 |
| EFFPLMN禁止网络号 | 6F7B | FPLMN | 禁用的PLMN | 禁止选择除中国移动以外的其他运营商,比如中国联通、中国卫通等 |
| EFLOCI位置信息 | 6F7E | LOCI | 位置信息 | 存储临时移动用户识别符、位置区信息等内容 |
| EFAD管理数据 | 6FAD | AD | 管理数据 | 包括关于不同类型SIM卡操作模式的信息。例如:常规模式(PLMN用户用于GSM网络操作),型号认证模式(允许ME在无线设备的认证期间的特殊应用);小区测试模式(在小区商用之前,进行小区测试),制造商特定模式(允许ME制造商在维护阶段进行特定的性能自动测试) |
| EFPHASE阶段 | 6FAE | PHASE | 阶段标识 | 标识SIM卡所处的阶段信息,比如是普通SIM卡还是STK卡等 |
| DFTELECOM | 7F10 | 电信目录 | | |
| EFADN缩位拨号 | 6F3A | AND | 电话簿 | 用于将电话记录存放在SIM卡中 |
| EFFDN固定拨号 | 6F3B | FDN | 固定拨号 | 包括固定拨号(FDN)和/或补充业务控制字串(SSC),还包括相关网络/承载能力的识别符和扩展记录的识别符,以及有关的α识别符 |
| EFSMS短消息 | 6F3C | SMS | 短消息 | 用于将短消息记录存放在SIM卡中 |
| EFCCP能力配置参数 | 6F3D | CCP | 能力配置参数 | 包括所需要的网络和承载能力的参数,以及当采用一个缩位拨号号码,固定拨号号码,MSISDN、最后拨号号码、服务拨号号码或禁止拨号方式等,建立呼叫时相关的ME配置 |
| EFMSISDN电话号码 | 6F40 | MSISDN | 移动基站国际综合业务网号 | 存放用户的手机号 |
| EFSMSP短信息参数 | 6F42 | SMSP | 短消息业务参数 | 包括短信中心号码等信息 |
| EFSMSS短信息状态 | 6F43 | SMSS | 短消息状态 | 这个标识是用来控制流量的 |
| EFLND最后拨号 | 6F44 | LND | 最后拨叫号码 | 存储最后拨叫号码 |
| EFExt1扩展文件1 | 6F4A | EXT1 | 扩展文件1 | 包括AND,MSISDN或LND的扩展数据 |
| EFExt2扩展文件2 | 6F4B | EXT2 | 扩展文件2 | 包含FDN的扩展数据 |
### 7. 如何判断是否有SD卡?
通过如下方法:`Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)`,如果返回true就是有sdcard,如果返回false则没有。
### 8. dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?
dvm指dalvik的虚拟机。每一个Android应用程序都拥有一个独立的Dalvik虚拟机实例,应用程序都在它自己的进程中运行。而每一个dvm都是在Linux 中的一个进程,所以说可以近似认为是同一个概念。
什么是android DVM:Dalvik是Google公司自己设计用于Android平台的Java虚拟机,每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。
Dalvik和Java虚拟机的区别
1.Dalvik主要是完成对象生命周期管理,堆栈管理,线程管理,安全和异常管理,以及垃圾回收等等重要功能。
2.Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。
3.不同于Java虚拟机运行java字节码,Dalvik虚拟机运行的是其专有的文件格式Dex
4.dex文件格式可以减少整体文件尺寸,提高I/O操作的类查找速度。
5.odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。
6.所有的Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制
7.有一个特殊的虚拟机进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成虚拟机的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。
### 9. Android程序与Java程序的区别?
Android程序用android sdk开发,java程序用javasdk开发。
Android SDK引用了大部分的Java SDK,少数部分被AndroidSDK抛弃,比如说界面部分,java.awt swing package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。android sdk 添加工具jar httpclient , pull opengl
### 10.启动应用后,改变系统语言,应用的语言会改变么?
这个一般是不会的,一般需要重启应用才能改变应用语言。但是对应应用来说如果做了国际化处理则支持如果没有处理那系统语言再更改也是无用的。
### 11.请介绍下adb、ddms、aapt的作用
adb是Android Debug Bridge ,Android调试桥的意思,ddms是Dalvik Debug Monitor Service,dalvik调试监视服务。aapt即AndroidAsset Packaging Tool,在SDK的build-tools目录下。该工具可以查看,创建,更新ZIP格式的文档附件(zip, jar, apk)。也可将资源文件编译成二进制文件,尽管我们没有直接使用过该工具,但是开发工具会使用这个工具打包apk文件构成一个Android 应用程序。
Android 的主要调试工具是adb(Android debuging bridge),ddms是一个在adb基础上的一个图形化工具。adb,它是一个命令行工具。而ddms功能与adb相同,只是它有一个图形化界面。对不喜欢命今操作方式的人来说是一个不错的选择。
### 12.ddms 和traceview的区别
简单的说ddms是一个程序执行查看器,在里面可以看见线程和堆栈等信息,traceView是程序性能分析器。
### 13.补充知识:TraceView的使用
#### 13.1 TraceView简介
Traceview是Android平台特有的数据采集和分析工具,它主要用于分析Android中应用程序的hotspot(瓶颈)。Traceview本身只是一个数据分析工具,而数据的采集则需要使用Android SDK中的Debug类或者利用DDMS工具。二者的用法如下:
开发者在一些关键代码段开始前调用Android SDK中Debug类的startMethodTracing函数,并在关键代码段结束前调用stopMethodTracing函数。这两个函数运行过程中将采集运行时间内该应用所有线程(注意,只能是Java线程)的函数执行情况,并将采集数据保存到/mnt/sdcard/下的一个文件中。开发者然后需要利用SDK中的Traceview工具来分析这些数据。
借助Android SDK中的DDMS工具。DDMS可采集系统中某个正在运行的进程的函数调用信息。对开发者而言,此方法适用于没有目标应用源代码的情况。DDMS工具中Traceview的使用如下图所示。

点击上图中所示按钮即可以采集目标进程的数据。当停止采集时,DDMS会自动触发Traceview工具来浏览采集数据。
下面,我们通过一个示例程序向读者介绍Debug类以及Traceview的使用。
实例程序如下图所示:界面有4个按钮,对应四个方法。

点击不同的方法会进行不同的耗时操作。
```java
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void method1(View view) {
int result = jisuan();
System.out.println(result);
}
private int jisuan() {
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
return 1;
}
public void method2(View view) {
SystemClock.sleep(2000);
}
public void method3(View view) {
int sum = 0;
for (int i = 0; i < 1000; i++) {
sum += i;
}
System.out.println("sum=" + sum);
}
public void method4(View view) {
Toast.makeText(this, "" + new Date(), 0).show();
}
}
```
我们分别点击按钮一次,要求找出最耗时的方法。点击前通过DDMS 启动 Start Method Profiling按钮。

然后依次点击4个按钮,都执行后再次点击上图中红框中按钮,停止收集数据。
接下来我们开始对数据进行分析。
当我们停止收集数据的时候会出现如下分析图表。该图表分为2大部分,上面分不同的行,每一行代表一个线程的执行耗时情况。main线程对应行的的内容非常丰富,而其他线程在这段时间内干得工作则要少得多。图表的下半部分是具体的每个方法执行的时间情况。显示方法执行情况的前提是先选中某个线程。

我们主要是分析main线程。
上面方法指标参数所代表的意思如下:
| 列名 | 描述 |
| :--------------------- | :---------------------------------- |
| Name | 该线程运行过程中所调用的函数名 |
| Incl Cpu Time | 某函数占用的CPU时间,包含内部调用其它函数的CPU时间 |
| Excl Cpu Time | 某函数占用的CPU时间,但不含内部调用其它函数所占用的CPU时间 |
| Incl Real Time | 某函数运行的真实时间(以毫秒为单位),内含调用其它函数所占用的真实时间 |
| Excl Real Time | 某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间 |
| Call+Recur Calls/Total | 某函数被调用次数以及递归调用占总调用次数的百分比 |
| Cpu Time/Call | 某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间 |
| Real Time/Call | 同CPU Time/Call类似,只不过统计单位换成了真实时间 |
我们为了找到最耗时的操作,那么可以通过点击Incl Cpu Time,让其按照时间的倒序排列。我点击后效果如下图:

通过分析发现:method1最耗时,耗时2338毫秒。

那么有了上面的信息我们可以进入我们的method1方法查看分析我们的代码了。
## Activity
### 1.什么是Activity?
四大组件之一,通常一个用户交互界面对应一个activity。activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件。
常见的Activity类型有FragmentActivitiy,ListActivity,TabAcitivty等。
如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity。
### 2.请描述一下Activity 生命周期
Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:onCreate、onStart、onResume、onPause、onStop、onDestroy
其实这些方法都是两两对应的,
onCreate创建与onDestroy销毁;
onStart可见与onStop不可见;
onResume可编辑(即焦点)与onPause;
这6个方法是相对应的,那么就只剩下一个onRestart方法了,这个方法在什么时候调用呢?
答案就是:在Activity被onStop后,但是没有被onDestroy,在再次启动此Activity时就调用onRestart(而不再调用onCreate)方法;如果被onDestroy了,则是调用onCreate方法。
### 3.如何保存Activity的状态?
Activity的状态通常情况下系统会自动保存的,只有当我们需要保存额外的数据时才需要使用到这样的功能。
一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会得到保留。
但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有该activity的实例对象了。如果之后这个activity重新回到前台, 之前所作的改变就会消失。为了避免此种情况的发生, 我们可以覆写onSaveInstanceState()方法。onSaveInstanceState()方法接受一个Bundle类型的参数, 开发者可以将状态数据存储到这个Bundle对象中, 这样即使activity被系统摧毁,当用户重新启动这个activity而调用它的onCreate()方法时, 上述的Bundle对象会作为实参传递给onCreate()方法, 开发者可以从Bundle对象中取出保存的数据, 然后利用这些数据将activity恢复到被摧毁之前的状态。
需要注意的是, onSaveInstanceState()方法并不是一定会被调用的, 因为有些场景是不需要保存状态数据的. 比如用户按下BACK键退出activity时, 用户显然想要关闭这个activity, 此时是没有必要保存数据以供下次恢复的, 也就是onSaveInstanceState()方法不会被调用. 如果调用onSaveInstanceState()方法, 调用将发生在onPause()或onStop()方法之前。
```java
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
```
### 4.两个Activity之间跳转时必然会执行的是哪几个方法?
一般情况下比如说有两个activity,分别叫A,B,当在A里面激活B组件的时候, A会调用 onPause()方法,然后B调用onCreate() ,onStart(), onResume()。这个时候B覆盖了窗体, A会调用onStop()方法. 如果B是个透明的,或者是对话框的样式, 就不会调用A的onStop()方法。
### 5.横竖屏切换时Activity的生命周期
此时的生命周期跟清单文件里的配置有关系。
1.不设置Activity的`android:configChanges`时,切屏会重新调用各个生命周期,默认首先销毁当前activity,然后重新加载。
2.设置Activity的`android:configChanges="orientation|keyboardHidden|screenSize"`时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。
通常在游戏开发, 屏幕的朝向都是写死的。
### 6.如何将一个Activity设置成窗口的样式
只需要给我们的Activity配置如下属性即可。
```xml
android:theme="@android:style/Theme.Dialog"
```
### 7.如何退出Activity?如何安全退出已调用多个Activity的Application?
1.通常情况用户退出一个Activity只需按返回键,我们写代码想退出activity直接调用finish()方法就行。
2.记录打开的Activity:每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
```java
//伪代码
List<Activity> lists;// 在application 全局的变量里面
lists = new ArrayList<Activity>();
lists.add(this);
for (Activity activity : lists) {
activity.finish();
}
lists.remove(this);
```
3.发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
```java
//给某个activity 注册接受接受广播的意图
registerReceiver(receiver, filter)
//如果过接受到的是 关闭activity的广播 就调用finish()方法把当前的activity finish()掉
```
4.递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
5.其实 也可以通过 intent的flag 来实现intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)激活一个新的activity。此时如果该任务栈中已经有该Activity,那么系统会把这个Activity上面的所有Activity干掉。其实相当于给Activity配置的启动模式为SingleTop。
### 8.请描述一下Activity的启动模式都有哪些以及各自的特点
启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。
Activity一共有以下四种launchMode:
- standard 默认启动模式
- singleTop 栈顶复用模式
- singleTask 栈内复用模式
- singleInstance 单例模式
我们可以在AndroidManifest.xml配置<activity>的android:launchMode属性为以上四种之一即可。
下面我们结合实例一一介绍这四种lanchMode:
#### 8.1 standard
standard模式是默认的启动模式,不用为<activity>配置android:launchMode属性即可,当然也可以指定值为standard。
我们将创建一个Activity,命名为FirstActivity,来演示一下标准的启动模式。FirstActivity代码如下:
```java
public class FirstActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first);
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText(this.toString());
Button button = (Button) findViewById(R.id.bt);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
}
```
FirstActivity界面中的TextView用于显示当前Activity实例的序列号,Button用于跳转到下一个FirstActivity界面。
然后我们连续点击几次按钮,将会出现下面的现象:

我们注意到都是FirstActivity的实例,但序列号不同,并且我们需要连续按后退键两次,才能回到第一个FirstActivity。standard模式的原理如下图所示:

如图所示,每次跳转系统都会在task中生成一个新的FirstActivity实例,并且放于栈结构的顶部,当我们按下后退键时,才能看到原来的FirstActivity实例。
这就是standard启动模式,不管有没有已存在的实例,都生成新的实例。
#### 8.2 singleTop
我们在上面的基础上为<activity>指定属性android:launchMode="singleTop",系统就会按照singleTop启动模式处理跳转行为。我们重复上面几个动作,将会出现下面的现象:


我们看到这个结果跟standard有所不同,三个序列号是相同的,也就是说使用的都是同一个FirstActivity实例;如果按一下后退键,程序立即退出,说明当前栈结构中只有一个Activity实例。singleTop模式的原理如下图所示:

正如上图所示,跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用。也许朋友们会有疑问,我只看到栈内只有一个Activity,如果是多个Activity怎么办,如果不是在栈顶会如何?我们接下来再通过一个示例来证实一下大家的疑问。
我们再新建一个Activity命名为SecondActivity,如下:
```java
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText(this.toString());
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
}
```
然后将之前的FirstActivity跳转代码改为:
```java
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
```
这时候,FirstActivity会跳转到SecondActivity,SecondActivity又会跳转到FirstActivity。演示结果如下:

我们看到,两个FirstActivity的序列号是不同的,证明从SecondActivity跳转到FirstActivity时生成了新的FirstActivity实例。原理图如下:

我们看到,当从SecondActivity跳转到FirstActivity时,系统发现存在有FirstActivity实例,但不是位于栈顶,于是重新生成一个实例。
这就是singleTop启动模式,如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。
#### 8.3 singleTask
在上面的基础上我们修改FirstActivity的属性android:launchMode="singleTask"。演示的结果如下:

我们注意到,在上面的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。singleTask模式的原理图如下图所示:

在图中的下半部分是SecondActivity跳转到FirstActivity后的栈结构变化的结果,我们注意到,SecondActivity消失了,没错,在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是将FirstActivity之上的Activity实例统统出栈,将FirstActivity变为栈顶对象,显示到幕前。也许朋友们有疑问,如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivity时,SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。
这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。
#### 8.4 singleInstance
这种启动模式比较特殊,因为它会启用一个新的栈结构,将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
我们修改FirstActivity的launchMode="standard",SecondActivity的launchMode="singleInstance",由于涉及到了多个栈结构,我们需要在每个Activity中显示当前栈结构的id,所以,我们为每个Activity添加如下代码:
```java
TextView taskIdView = (TextView) findViewById(R.id.taskIdView);
taskIdView.setText("current task id: " + this.getTaskId());
```
然后我们再演示一下这个流程:

我们发现这两个Activity实例分别被放置在不同的栈结构中,关于singleInstance的原理图如下:

我们看到从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到FirstActivity,这个时候系统会在原始栈结构中生成一个FirstActivity实例,然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到FirstActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。
如果我们修改FirstActivity的launchMode值为singleTop、singleTask、singleInstance中的任意一个,流程将会如图所示:

singleInstance启动模式可能是最复杂的一种模式,为了帮助大家理解,我举一个例子,假如我们有一个share应用,其中的ShareActivity是入口Activity,也是可供其他应用调用的Activity,我们把这个Activity的启动模式设置为singleInstance,然后在其他应用中调用。我们编辑ShareActivity的配置:
```xml
<activity
android:name=".ShareActivity"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SINGLE_INSTANCE_SHARE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
```
然后我们在其他应用中这样启动该Activity:
```java
Intent intent = new Intent("android.intent.action.SINGLE_INSTANCE_SHARE");
startActivity(intent);
```
当我们打开ShareActivity后再按后退键回到原来界面时,ShareActivity做为一个独立的个体存在,如果这时我们打开share应用,无需创建新的ShareActivity实例即可看到结果,因为系统会自动查找,存在则直接利用。大家可以在ShareActivity中打印一下taskId,看看效果。关于这个过程,原理图如下:

## Service
### 1.Service是否在main thread中执行, service里面是否能执行耗时的操作?
默认情况,如果没有显示的指servic所运行的进程, Service和activity是运行在当前app所在进程的main thread(UI主线程)里面。
service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )。
特殊情况 ,可以在清单文件配置 service 执行所在的进程,让service在另外的进程中执行。
```xml
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>
```
### 2.Activity怎么和Service绑定,怎么在Activity中启动自己对应的Service?
Activity通过bindService(Intent service, ServiceConnection conn,int flags)跟Service进行绑定,当绑定成功的时候Service会将代理对象通过回调的形式传给conn,这样我们就拿到了Service提供的服务代理对象。
在Activity中可以通过startService和bindService方法启动Service。一般情况下如果想获取Service的服务对象那么肯定需要通过bindService()方法,比如音乐播放器,第三方支付等。如果仅仅只是为了开启一个后台任务那么可以使用startService()方法。
### 3.请描述一下Service的生命周期
service有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同的使用方法生命周期方法也不同。
非绑定模式:当第一次调用startService的时候执行的方法依次为onCreate()、onStartCommand(),当Service关闭的时候调用onDestory方法。
绑定模式:第一次bindService()的时候,执行的方法为onCreate()、onBind()解除绑定的时候会执行onUnbind()、onDestory()。
上面的两种生命周期是在相对单纯的模式下的情形。我们在开发的过程中还必须注意Service实例只会有一个,也就是说如果当前要启动的Service已经存在了那么就不会再次创建该Service当然也不会调用onCreate()方法。
一个Service可以被多个客户进行绑定,只有所有的绑定对象都执行了onBind()方法后该Service才会销毁,不过如果有一个客户执行了onStart()方法,那么这个时候如果所有的bind客户都执行了unBind()该Service也不会销毁。
Service的生命周期图如下所示,帮助大家记忆。

### 4.什么是IntentService?有何优点?
我们通常只会使用Service,可能IntentService对大部分同学来说都是第一次听说。那么看了下面的介绍相信你就不再陌生了。如果你还是不了解那么在面试的时候你就坦诚说没用过或者不了解等。并不是所有的问题都需要回答上来的。
#### IntentService简介
IntentService是Service的子类,比普通的Service增加了额外的功能。先看Service本身存在两个问题:
service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;
service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;
#### IntentService特征
会创建独立的worker线程来处理所有的Intent请求;
会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
为Service的onBind()提供默认实现,返回null;
为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
#### 使用IntentService
本人写了一个IntentService的使用例子供参考。该例子中一个MainActivity一个MyIntentService,这两个类都是四大组件当然需要在清单文件中注册。这里只给出核心代码:
MainActivity.java
```java
public void click(View view){
Intent intent = new Intent(this, MyIntentService.class);
intent.putExtra("start", "MyIntentService");
startService(intent);
}
MyIntentService.javapublic class MyIntentService extends IntentService {
private String ex = "";
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
Toast.makeText(MyIntentService.this, "-e " + ex, Toast.LENGTH_LONG).show();
}
};
public MyIntentService(){
super("MyIntentService");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
ex = intent.getStringExtra("start");
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(Intent intent) {
/
* 模拟执行耗时任务
* 该方法是在子线程中执行的,因此需要用到handler跟主线程进行通信
*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.sendEmptyMessage(0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
```
运行后效果如下:

### 5.说说Activity、Intent、Service是什么关系
他们都是Android开发中使用频率最高的类。其中Activity和Service都是Android四大组件之一。他俩都是Context类的子类ContextWrapper的子类,因此他俩可以算是兄弟关系吧。不过兄弟俩各有各自的本领,Activity负责用户界面的显示和交互,Service负责后台任务的处理。Activity和Service之间可以通过Intent传递数据,因此可以把Intent看作是通信使者。
### 6.Service和Activity在同一个线程吗
对于同一app来说默认情况下是在同一个线程中的,mainThread (UI Thread)。
### 7.Service里面可以弹吐司么
可以的。弹吐司有个条件就是得有一个Context上下文,而Service本身就是Context的子类,因此在Service里面弹吐司是完全可以的。比如我们在Service中完成下载任务后可以弹一个吐司通知用户。
## BroadCastReceiver
### 1.请描述一下BroadcastReceiver
BroadCastReceiver是Android四大组件之一,主要用于接收系统或者app发送的广播事件。广播分两种:有序广播和无序广播。
内部通信实现机制:通过Android系统的Binder机制实现通信。
无序广播:完全异步,逻辑上可以被任何广播接收者接收到。优点是效率较高。缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播intent的传播。
有序广播:按照被接收者的优先级顺序,在被接收者中依次传播。比如有三个广播接收者A,B,C,优先级是A > B> C。那这个消息先传给A,再传给B,最后传给C。每个接收者有权终止广播,比如B终止广播,C就无法接收到。此外A接收到广播后可以对结果对象进行操作,当广播传给B时,B可以从结果对象中取得A存入的数据。在通过Context.sendOrderedBroadcast(intent, receiverPermission,resultReceiver, scheduler, initialCode, initialData, initialExtras)时我们可以指定resultReceiver广播接收者,这个接收者我们可以认为是最终接收者,通常情况下如果比他优先级更高的接收者如果没有终止广播,那么他的onReceive会被执行两次,第一次是正常的按照优先级顺序执行,第二次是作为最终接收者接收。如果比他优先级高的接收者终止了广播,那么他依然能接收到广播。
在我们的项目中经常使用广播接收者接收系统通知,比如开机启动、sd挂载、低电量、外播电话、锁屏等。
如果我们做的是播放器,那么监听到用户锁屏后我们应该将我们的播放之暂停等。
### 2.在manifest和代码中如何注册和使用BroadcastReceiver
在清单文件中注册广播接收者称为静态注册,在代码中注册称为动态注册。静态注册的广播接收者只要app在系统中运行则一直可以接收到广播消息,动态注册的广播接收者当注册的Activity或者Service销毁了那么就接收不到广播了。
静态注册:在清单文件中进行如下配置
```xml
<receiver android:name=".BroadcastReceiver1" >
<intent-filter>
<action android:name="android.intent.action.CALL" >
</action>
</intent-filter>
</receiver>
```
动态注册:在代码中进行如下注册
```java
receiver = new BroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(CALL_ACTION);
context.registerReceiver(receiver, intentFilter);
```
### 3.BroadCastReceiver的生命周期
a. 广播接收者的生命周期非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁;
b. 广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框;
c. 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉;
d. 耗时的较长的工作最好放在服务中完成;
## ContentProvider
### 1.请介绍下ContentProvider是如何实现数据共享的
在Android中如果想将自己应用的数据(一般多为数据库中的数据)提供给第三发应用,那么我们只能通过ContentProvider来实现了。
ContentProvider是应用程序之间共享数据的接口。使用的时候首先自定义一个类继承ContentProvider,然后覆写query、insert、update、delete等方法。因为其是四大组件之一因此必须在AndroidManifest文件中进行注册。
```xml
<provider
android:name="com.jackchan.contenProvider.provider.PersonContentProvider"
android:authorities="com.itheima.person"
android:exported="true"/>
```
第三方可以通过ContentResolver来访问该Provider。
### 2.请介绍下Android的数据存储方式
- File存储
- SharedPreference存储
- ContentProvider存储
- SQLiteDataBase存储
- 网络存储
### 3.为什么要用ContentProvider?它和sql的实现上有什么差别?
ContentProvider屏蔽了数据存储的细节,内部实现对用户完全透明,用户只需要关心操作数据的uri就可以了,ContentProvider可以实现不同app之间共享。
Sql也有增删改查的方法,但是sql只能查询本应用下的数据库。而ContentProvider 还可以去增删改查本地文件. xml文件的读取等。
### 4、说说ContentProvider、ContentResolver、ContentObserver之间的关系
- ContentProvider 内容提供者,用于对外提供数据
- ContentResolver.notifyChange(uri)发出消息
- ContentResolver 内容解析者,用于获取内容提供者提供的数据
- ContentObserver 内容监听器,可以监听数据的改变状态
- ContentResolver.registerContentObserver()监听消息
## Android中的布局
### 1.Android中常用的布局都有哪些
- FrameLayout
- RelativeLayout
- LinearLayout
- AbsoluteLayout
- TableLayout
- GridLayout
### 2.谈谈UI中, Padding和Margin有什么区别?
android:padding和android:layout_margin的区别,其实概念很简单,padding是站在父view的角度描述问题,它规定它里面的内容必须与这个父view边界的距离。margin则是站在自己的角度描述问题,规定自己和其他(上下左右)的view之间的距离,如果同一级只有一个view,那么它的效果基本上就和padding一样了。
## ListView
### 1.ListView如何提高其效率?
- 复用ConvertView
- 自定义静态类ViewHolder
- 使用分页加载
- 使用WeakRefrence引用ImageView对象
### 2.当ListView数据集改变后,如何更新ListView
使用该ListView的adapter的notifyDataSetChanged()方法。该方法会使ListView重新绘制。
### 3.ListView如何实现分页加载
设置ListView的滚动监听器:`setOnScrollListener(new OnScrollListener{….})`。在监听器中有两个方法: 滚动状态发生变化的方法(onScrollStateChanged)和listView被滚动时调用的方法(onScroll)
在滚动状态发生改变的方法中,有三种状态:
- 手指按下移动的状态:SCROLL_STATE_TOUCH_SCROLL: // 触摸滑动
- 惯性滚动(滑翔(flgin)状态):SCROLL_STATE_FLING: // 滑翔
- 静止状态:SCROLL_STATE_IDLE: // 静止
对不同的状态进行处理:
分批加载数据,只关心静止状态:关心最后一个可见的条目,如果最后一个可见条目就是数据适配器(集合)里的最后一个,此时可加载更多的数据。在每次加载的时候,计算出滚动的数量,当滚动的数量大于等于总数量的时候,可以提示用户无更多数据了。
### 4.ListView可以显示多种类型的条目吗
这个当然可以的,ListView显示的每个条目都是通过baseAdapter的getView(int position, View convertView, ViewGroup parent)来展示的,理论上我们完全可以让每个条目都是不同类型的view,除此之外adapter还提供了getViewTypeCount()和getItemViewType(int position)两个方法。在getView方法中我们可以根据不同的viewtype加载不同的布局文件。
### 5.ListView如何定位到指定位置
可以通过ListView提供的`lv.setSelection(48);`方法。
### 6.当在ScrollView中如何嵌入ListView
通常情况下我们不会在ScrollView中嵌套ListView,但是如果面试官非让我嵌套的话也是可以的。
在ScrollView添加一个ListView会导致listview控件显示不全,通常只会显示一条,这是因为两个控件的滚动事件冲突导致。所以需要通过listview中的item数量去计算listview的显示高度,从而使其完整展示,如下提供一个方法供大家参考。
```java
lv = (ListView) findViewById(R.id.lv);
adapter = new MyAdapter();
lv.setAdapter(adapter);
setListViewHeightBasedOnChildren(lv);
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
params.height += 5;// if without this statement,the listview will be a little short
listView.setLayoutParams(params);
}
```
### 7.ListView中如何优化图片
图片的优化策略比较多。
#### 处理图片的方式:
如果ListView中自定义的Item中有涉及到大量图片的,一定要对图片进行细心的处理,因为图片占的内存是ListView项中最头疼的,处理图片的方法大致有以下几种:
- 不要直接拿路径就去循环BitmapFactory.decodeFile;使用Options保存图片大小、不要加载图片到内存去。
- 对图片一定要经过边界压缩尤其是比较大的图片,如果你的图片是后台服务器处理好的那就不需要了
- 在ListView中取图片时也不要直接拿个路径去取图片,而是以WeakReference(使用WeakReference代替强引用。比如可以使用WeakReference mContextRef)、SoftReference、WeakHashMap等的来存储图片信息。
- 在getView中做图片转换时,产生的中间变量一定及时释放
#### 异步加载图片基本思想:
- 先从内存缓存中获取图片显示(内存缓冲)
- 获取不到的话从SD卡里获取(SD卡缓冲)
- 都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)
原理:
优化一:先从内存中加载,没有则开启线程从SD卡或网络中获取,这里注意从SD卡获取图片是放在子线程里执行的,否则快速滑屏的话会不够流畅。
优化二:于此同时,在adapter里有个busy变量,表示listview是否处于滑动状态,如果是滑动状态则仅从内存中获取图片,没有的话无需再开启线程去外存或网络获取图片。
优化三:ImageLoader里的线程使用了线程池,从而避免了过多线程频繁创建和销毁,如果每次总是new一个线程去执行这是非常不可取的,好一点的用的AsyncTask类,其实内部也是用到了线程池。在从网络获取图片时,先是将其保存到sd卡,然后再加载到内存,这么做的好处是在加载到内存时可以做个压缩处理,以减少图片所占内存。
### 8.ListView中图片错位的问题是如何产生的
图片错位问题的本质源于我们的listview使用了缓存convertView,假设一种场景,一个listview一屏显示九个item,那么在拉出第十个item的时候,事实上该item是重复使用了第一个item,也就是说在第一个item从网络中下载图片并最终要显示的时候,其实该item已经不在当前显示区域内了,此时显示的后果将可能在第十个item上输出图像,这就导致了图片错位的问题。所以解决之道在于可见则显示,不可见则不显示。
### 9.Java中引用类型都有哪些
Java中对象的引用分为四种级别,这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
**强引用(StrongReference)**
这个就不多说,我们写代码天天在用的就是强引用。如果一个对象被被人拥有强引用,那么垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
Java的对象是位于heap中的,heap中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是强、软、弱、和虚。对于对象是属于哪种可及的对象,由他的最强的引用决定。如下代码:
```java
String abc=new String("abc"); //1
SoftReference<String> softRef=new SoftReference<String>(abc); //2
WeakReference<String> weakRef = new WeakReference<String>(abc); //3
abc=null; //4
softRef.clear();//5
```
第一行在heap堆中创建内容为“abc”的对象,并建立abc到该对象的强引用,该对象是强可及的。
第二行和第三行分别建立对heap中对象的软引用和弱引用,此时heap中的abc对象已经有3个引用,显然此时abc对象仍是强可及的。 第四行之后heap中对象不再是强可及的,变成软可及的。 第五行执行之后变成弱可及的。
**软引用(SoftReference)**
如果一个对象只具有软引用,那么如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集
取决于gc的算法和gc运行时可用内存的大小。当gc决定要收集软引用时执行以下过程,以上面的softRef为例:
- 首先将softRef的referent(abc)设置为null,不再引用heap中的new String("abc")对象。
- 将heap中的newString("abc")对象设置为可结束的(finalizable)。
- 当heap中的new String("abc")对象的finalize()方法被运行而且该对象占用的内存被释放, softRef被添加到它的ReferenceQueue(如果有的话)中。
注意:对ReferenceQueue软引用和弱引用可以有可无,但是虚引用必须有。被 SoftReference 指到的对象,即使没有任何 Direct Reference,也不会被清除。一直要到 JVM 内存不足且没有Direct Reference 时才会清除,SoftReference 是用来设计 object-cache 之用的。如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误(OutOfMemoryError)。file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
**弱引用(WeakReference)**
如果一个对象只具有弱引用,那该类就是可有可无的对象,因为只要该对象被gc扫描到了随时都会把它干掉。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
**虚引用(PhantomReference)**
"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被垃圾回收的活动。
虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
建立虚引用之后通过get方法返回结果始终为null,通过源代码你会发现,虚引用通向会把引用的对象写进referent,只是get方法返回结果为null。先看一下和gc交互的过程再说一下他的作用。
1.不把referent设置为null, 直接把heap中的newString("abc")对象设置为可结束的(finalizable)。
2.与软引用和弱引用不同, 先把PhantomRefrence对象添加到它的ReferenceQueue中.然后在释放虚可及的对象。
## JNI&NDK
1.在Android中如何调用C语言
当我们的Java需要调用C语言的时候可以通过JNI的方式,Java Native Interface。Android提供了对JNI的支持,因此我们在Android中可以使用JNI调用C语言。在Android开发目录的libs目录下添加xxx.so文件,不过xxx.so文件需要放在对应的CPU架构名目录下,比如armeabi,x86等。
在Java代码需要通过System.*loadLibrary*(libName);加载so文件。同时C语言中的方法在java中必须以native关键字来声明。普通Java方法调用这个native方法接口,虚拟机内部自动调用so文件中对应的方法。
2.请介绍一下NDK
1.NDK 是一系列工具的集合
NDK 提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so 和java 应用一起打包成apk。NDK 集成了交叉编译器,并提供了相应的mk 文件隔离CPU、平台、ABI 等差异,开发人员只需要简单修改mk 文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
2.NDK 提供了一份稳定、功能有限的API 头文件声明
Google 明确声明该API 是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK 中看出,这些API支持的功能非常有限,包含有:C 标准库(libc)、标准数学库(libm)、压缩库(libz)、Log 库(liblog)。
3、JNI调用常用的两个参数
JNIEnv*env, jobject obj
第一个是指向虚拟机对象的指针,是一个二级指针。里面封装了很多方法和中间变量供我们使用。
第二个代表着调用该方法的Java对象的C语言表示。
## Android中的网络访问
### 1、Android中如何访问网络
Android提供了org.apache.http.HttpClientConnection和java.net.HttpURLConnection两个连接网络对象。使用哪个都行,具体要看企业领导的要求了。 除此之外一般我比较喜欢使用xUtils中的HttpUtils功能,该模块底层使用的就是org.apache.http.client.HttpClient,使用起来非常方便。
### 2、如何解析服务器传来的JSON文件
在Android中内置了JSON的解析API,在org.json包中包含了如下几个类:JSONArray、JSONObject、JSONStringer、JSONTokener和一个异常类JSONException。
1、JSON解析步骤
1)读取网络文件数据并转为一个json字符串
```java
InputStreamin = conn.getInputStream();
StringjsonStr = DataUtil.Stream2String(in);//将流转换成字符串的工具类
```
2)将字符串传入相应的JSON构造函数中
- 通过构造函数将json字符串转换成json对象
```java
JSONObject jsonObject = new JSONObject(jsonStr);
```
- 通过构造函数将json字符串转换成json数组:
JSONArray array = new JSONArray(jsonStr);
3)解析出JSON中的数据信息:
- 从json对象中获取你所需要的键所对应的值
```java
JSONObject json=jsonObject.getJSONObject("weatherinfo");
Stringcity = json.getString("city");
Stringtemp = json.getString("temp")
```
- 遍历JSON数组,获取数组中每一个json对象,同时可以获取json对象中键对应的值
```java
for(int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
Stringtitle=obj.getString("title");
Stringdescription=obj.getString("description");
}
```
2、生成JSON对象和数组
1)生成JSON:
方法1、创建一个map,通过构造方法将map转换成json对象
```java
Map<String,Object> map = new HashMap<String, Object>();
map.put("name","zhangsan");
map.put("age",24);
JSONObjectjson = new JSONObject(map);
```
方法2、创建一个json对象,通过put方法添加数据
```java
JSONObjectjson=new JSONObject();
json.put("name","zhangsan");
json.put("age",24);
```
2)生成JSON数组:
创建一个list,通过构造方法将list转换成json对象
```java
Map<String,Object> map1 = new HashMap<String, Object>();
map1.put("name","zhangsan");
map1.put("age",24);
Map<String,Object> map2 = new HashMap<String, Object>();
map2.put("name","lisi");
map2.put("age",25);
List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
list.add(map1);
list.add(map2);
JSONArrayarray=new JSONArray(list);
System.out.println(array.toString());
```
### 3、如何解析服务器传来的XML格式数据
Android为我们提供了原生的XML解析和生成支持。
1、XML解析
- 获取解析器: Xml.newPullParser()
- 设置输入流: setInput()
- 获取当前事件类型: getEventType()
- 解析下一个事件, 获取类型: next()
- 获取标签名: getName()
- 获取属性值: getAttributeValue()
- 获取下一个文本: nextText()
- 获取当前文本: getText()
5种事件类型: START_DOCUMENT, END_DOCUMENT, START_TAG,END_TAG, TEXT
示例代码:
```java
public List<Person>getPersons(InuptStream in){
XmlPullParserparser=Xml.newPullParser();//获取解析器
parser.setInput(in,"utf-8");
for(inttype=){ //循环解析
}
}
```
2、XML生成
- 获取生成工具: Xml.newSerializer()
- 设置输出流: setOutput()
- 开始文档: startDocument()
- 结束文档: endDocument()
- 开始标签: startTag()
- 结束标签: endTag()
- 属性: attribute()
- 文本: text()
示例代码:
```java
XmlSerializer serial=Xml.newSerializer();//获取xml序列化工具
serial.setOuput(put,"utf-8");
serial.startDocument("utf-8",true);
serial.startTag(null,"persons");
for(Person p:persons){
serial.startTag(null,"persons");
serial.attribute(null,"id",p.getId().toString());
serial.startTag(null,"name");
serial.attribute(null,"name",p.getName().toString());
serial.endTag(null,"name");
serial.startTag(null,"age");
serial.attribute(null,"age",p.getAge().toString());
serial.endTag(null,"age");
serial.endTag(null,"persons");
}
```
### 4、如何从网络上加载一个图片显示到界面
可以通过BitmapFactory.decodeStream(inputStream);方法将图片转换为bitmap,然后通过imageView.setImageBitmap(bitmap);将该图片设置到ImageView中。这是原生的方法,还可以使用第三方开源的工具来实现,比如使用SmartImageView作为ImageView控件,然后直接设置一个url地址即可。也可以使用xUtils中的BitmapUtils工具。
### 5、如何播放网络视频
除了使用Android提供的MediaPlayer和VideoView外通常还可以使用第三方开源万能播放器,VitamioPlayer。该播放器兼容性好,支持几乎所有主流视频格式。
## Intent
### 1、Intent传递数据时,可以传递哪些类型数据?
Intent可以传递的数据类型非常的丰富,java的基本数据类型和String以及他们的数组形式都可以,除此之外还可以传递实现了Serializable和Parcelable接口的对象。
### 2、Serializable和Parcelable的区别
- 在使用内存的时候,Parcelable 类比Serializable性能高,所以推荐使用Parcelable类。
- Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
- Parcelable不能使用在要将数据存储在磁盘上的情况。尽管Serializable效率低点,但在这种情况下,还是建议你用Serializable 。
-
实现:
1、Serializable 的实现,只需要继承Serializable 即可。这只是给对象打了一个标记,系统会自动将其序列化。
2、Parcelabel 的实现,需要在类中添加一个静态成员变量 CREATOR,这个变量需要继承 Parcelable.Creator 接口。
```java
public class MyParcelable implements Parcelable {
private int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
private MyParcelable(Parcel in) {
mData = in.readInt();
}
}
```
### 3、请描述一下Intent 和 IntentFilter
Android 中通过 Intent 对象来表示一条消息,一个 Intent对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
通过Intent 可以实现各种系统组件的调用与激活。
IntentFilter: 可以理解为邮局或者是一个信笺的分拣系统… 这个分拣系统通过3个参数来识别
- Action: 动作view
- Data: 数据uri uri
- Category : 而外的附加信息
Action 匹配
Action 是一个用户定义的字符串,用于描述一个 Android 应用程序组件,一个 IntentFilter 可以包含多个 Action。在 AndroidManifest.xml 的 Activity 定义时可以在其 <intent-filter >节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,
例如:
```xml
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<actionandroid:name="cn.itheima.action" />
……
</intent-filter>
```
如果我们在启动一个 Activity 时使用这样的Intent 对象
```
Intentintent =new Intent();
intent.setAction("cn.itheima.action");
```
那么所有的 Action 列表中包含了“cn.itheima”的 Activity 都将会匹配成功。 Android 预定义了一系列的 Action 分别表示特定的系统动作。这些Action 通过常量的方式定义在 android.content. Intent中,以“ACTION_”开头。我们可以在 Android 提供的文档中找到它们的详细说明。
URI 数据匹配
一个 Intent 可以通过 URI 携带外部数据给目标组件。在 <intent-filter >节点中,通过 <data/>节点匹配外部数据。
mimeType 属性指定携带外部数据的数据类型,scheme 指定协议,host、port、path 指定数据的位置、端口、和路径。如下:
```xml
<data android:mimeType="mimeType"
android:scheme="scheme"
android:host="host"
android:port="port"
android:path="path"/>
```
电话的uri tel:12345
自己定义的uri itcast://cn.itcast/person/10
如果在 Intent Filter 中指定了这些属性,那么只有所有的属性都匹配成功时 URI 数据匹配才会成功。
Category 类别匹配
<intent-filter >节点中可以为组件定义一个 Category 类别列表,当 Intent 中包含这个列表的所有项目时 Category 类别匹配才会成功。
## Fragment1、Fragment跟Activity之间是如何传值的
当Fragment跟Activity绑定之后,在Fragment中可以直接通过getActivity()方法获取到其绑定的Activity对象,这样就可以调用Activity的方法了。在Activity中可以通过如下方法获取到Fragment实例:
```java
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
Fragment fragment = fragmentManager.findFragmentById(id);
```
获取到Fragment之后就可以调用Fragment的方法。也就实现了通信功能。
2、描述一下Fragment的生命周期

## 能否在子线程中更新UI
可以的,在onCreate()的setContentView()后new一个Thread去更新UI是不会报错的,但是延迟1s后再更新UI就会报错,这是因为在onCreate()的时候ViewRoot的requestLayout()方法没有执行,layout布局文件还没有创建完成。而ViewRoot的requestLayout()方法中才会调用checkThread()方法检查当前是否是主线程,不是的话就抛CalledFromWrongThreadException。Android中的定义是:不建议在子线程中更新UI,否则会产生不可预知的错误
=========================
gitextract_bgwjn77o/
├── LICENSE
├── README.md
└── docs/
├── .nojekyll
├── android/
│ ├── Android-Interview/
│ │ ├── .gitignore
│ │ ├── Activity/
│ │ │ ├── Activity Task和Process.md
│ │ │ ├── App优雅退出.md
│ │ │ ├── README.md
│ │ │ ├── onCreate源码分析.md
│ │ │ ├── onSaveInstanceState源码内核分析.md
│ │ │ ├── 为什么service里面startActivity抛异常.md
│ │ │ ├── 深入理解Activity启动流程.md
│ │ │ ├── 深刻剖析activity启动模式-1.md
│ │ │ ├── 深刻剖析activity启动模式-2.md
│ │ │ └── 深刻剖析activity启动模式-3.md
│ │ ├── Android/
│ │ │ ├── Android基础面试核心内容.md
│ │ │ ├── Android视频教程.md
│ │ │ ├── Android面试精华题目总结.md
│ │ │ ├── Android面试重点.md
│ │ │ ├── Android面试题-1.md
│ │ │ ├── Android面试题-2.md
│ │ │ ├── Android高级面试10大开源框架源码解析.md
│ │ │ ├── BAT大咖助力全面升级Android面试.md
│ │ │ ├── README.md
│ │ │ ├── 平台架构.md
│ │ │ └── 接口安全.md
│ │ ├── HR/
│ │ │ ├── README.md
│ │ │ ├── 人事面试宝典.md
│ │ │ ├── 人事面试宝典一之自我介绍.md
│ │ │ └── 人事面试宝典二之离职.md
│ │ ├── Java/
│ │ │ ├── 115个Java面试题及回答.md
│ │ │ ├── 66道经典的Java基础面试题集锦.md
│ │ │ ├── J2SE基础面试核心内容.md
│ │ │ ├── J2SE高级面试核心内容.md
│ │ │ ├── Java面试题-1.md
│ │ │ ├── Java面试题-2.md
│ │ │ ├── Java高级软件工程师面试考纲.md
│ │ │ ├── README.md
│ │ │ ├── 数据库求差.md
│ │ │ └── 深拷贝浅拷贝.md
│ │ ├── README.md
│ │ ├── SUMMARY.md
│ │ ├── Service/
│ │ │ ├── Android面试题-Service.md
│ │ │ ├── Android面试题-Service不死之身.md
│ │ │ ├── IntentService源码分析.md
│ │ │ └── README.md
│ │ ├── book.json
│ │ ├── 开发遇到的问题/
│ │ │ ├── Context原理分析.md
│ │ │ ├── README.md
│ │ │ ├── ViewPager和Fragment使用过程中会遇到哪些问题.md
│ │ │ ├── 手把手教你如何解决as jar包冲突.md
│ │ │ ├── 机型适配之痛.md
│ │ │ ├── 终极解决ViewPager.setCurrentItem中间页面过多解决方案.md
│ │ │ ├── 解决字体适配.md
│ │ │ ├── 软键盘顶出去解决方案.md
│ │ │ └── 迭代开发的时候如何向前兼容新旧接口?.md
│ │ ├── 性能优化/
│ │ │ ├── Android应用UI性能分析.md
│ │ │ ├── App应用启动分析与优化.md
│ │ │ ├── README.md
│ │ │ ├── 与IPC机制相关面试题.md
│ │ │ ├── 与性能优化相关试题一.md
│ │ │ ├── 与性能优化相关试题三.md
│ │ │ ├── 与性能优化相关试题二.md
│ │ │ └── 内存泄漏监测.md
│ │ ├── 源码分析/
│ │ │ ├── Android源码编译实现静默安装和静默偷拍.md
│ │ │ ├── README.md
│ │ │ ├── Volley源码剖析.md
│ │ │ ├── okhttp内核剖析.md
│ │ │ └── 注解框架内部实现原理.md
│ │ ├── 登陆注册/
│ │ │ ├── Oauth的实现原理.md
│ │ │ ├── README.md
│ │ │ ├── Token的实际意义.md
│ │ │ └── 微信扫码登录内部实现原理.md
│ │ ├── 经验分享/
│ │ │ ├── 2016年4月某公司面试题及面试流程.md
│ │ │ ├── 2017届实习生招聘面经.md
│ │ │ ├── Andorid-15k+的面试题.md
│ │ │ ├── Android 暑期实习生面试经验谈.md
│ │ │ ├── Android 曲折的求职之路.md
│ │ │ ├── BAT无线工程师面试流程详细解析.md
│ │ │ ├── README.md
│ │ │ ├── 一个五年Android开发者百度、阿里、聚美、映客的面试心经.md
│ │ │ ├── 一个程序员的血泪史.md
│ │ │ ├── 互联网公司面试经验总结.md
│ │ │ ├── 互联网巨头BAT3内部员工的真实状况.md
│ │ │ ├── 史上最全 Android 面试资料集合.md
│ │ │ ├── 国内一线互联网公司内部面试题库.md
│ │ │ ├── 工作三年后,我选择离开腾讯.md
│ │ │ ├── 我为什么离开锤子科技?.md
│ │ │ ├── 我为什么要离开华为?.md
│ │ │ ├── 扫清Android面试障碍.md
│ │ │ ├── 技术硬碰硬—阳哥带你玩转上海Android招聘市场.md
│ │ │ ├── 杭州找 Android 工作的点点滴滴.md
│ │ │ ├── 给培训班出来的一点不成熟的小建议.md
│ │ │ ├── 腾讯公司程序员面试题及答案详解.md
│ │ │ ├── 阿里+百度+CVTE面经合集.md
│ │ │ └── 面试心得与总结:BAT、网易、蘑菇街 .md
│ │ ├── 网络编程/
│ │ │ ├── Android客户端和服务端如何使用Token和Session.md
│ │ │ ├── README.md
│ │ │ ├── 推送原理.md
│ │ │ ├── 简单阐述一下及时推送原理?.md
│ │ │ └── 阐述一下对XMPP协议理解以及优缺点?.md
│ │ └── 面试技巧/
│ │ ├── README.md
│ │ ├── 我在面试中最喜欢问开发者的问题,和回答思路.md
│ │ ├── 程序员面试宝典.md
│ │ └── 罗永浩新东方万字求职信.md
│ ├── AndroidNote/
│ │ ├── AdavancedPart/
│ │ │ ├── 1.热修复实现(一).md
│ │ │ ├── 2.热修复实现(二).md
│ │ │ ├── 3.热修复_addAssetPath不同版本区别原因(三).md
│ │ │ ├── ART与Dalvik.md
│ │ │ ├── Android WorkManager.md
│ │ │ ├── Android6.0权限系统.md
│ │ │ ├── Android卸载反馈.md
│ │ │ ├── Android启动模式详解.md
│ │ │ ├── Android开发不申请权限来使用对应功能.md
│ │ │ ├── Android开发中的MVP模式详解.md
│ │ │ ├── ApplicationId vs PackageName.md
│ │ │ ├── BroadcastReceiver安全问题.md
│ │ │ ├── ConstraintLaayout简介.md
│ │ │ ├── Handler导致内存泄露分析.md
│ │ │ ├── Library项目中资源id使用case时报错.md
│ │ │ ├── Mac下配置adb及Android命令.md
│ │ │ ├── MaterialDesign使用.md
│ │ │ ├── RecyclerView专题.md
│ │ │ ├── 如何让Service常驻内存.md
│ │ │ ├── 屏幕适配之百分比方案详解.md
│ │ │ ├── 布局优化.md
│ │ │ ├── 性能优化.md
│ │ │ ├── 注解使用.md
│ │ │ └── 通过Hardware Layer提高动画性能.md
│ │ ├── AndroidStudioCourse/
│ │ │ ├── Android Studio你可能不知道的操作.md
│ │ │ ├── AndroidStudio中进行ndk开发.md
│ │ │ ├── AndroidStudio使用教程(第一弹).md
│ │ │ ├── AndroidStudio使用教程(第七弹).md
│ │ │ ├── AndroidStudio使用教程(第三弹).md
│ │ │ ├── AndroidStudio使用教程(第二弹).md
│ │ │ ├── AndroidStudio使用教程(第五弹).md
│ │ │ ├── AndroidStudio使用教程(第六弹).md
│ │ │ ├── AndroidStudio使用教程(第四弹).md
│ │ │ └── AndroidStudio提高Build速度.md
│ │ ├── Android基础/
│ │ │ ├── Activity详细解析.md
│ │ │ ├── Android-SQLite的基本使用.md
│ │ │ ├── Android中相机与相册的详细使用.md
│ │ │ ├── Android异步任务机制之AsycTask.md
│ │ │ ├── Android数据存储的五种方式.md
│ │ │ ├── Android获取SHA1.md
│ │ │ ├── Android跟随手指移动的view.md
│ │ │ ├── BroadcastReceiver详细解析.md
│ │ │ ├── ContentProvider实例详解.md
│ │ │ ├── Handler,Looper,MessageQueue关系.md
│ │ │ ├── IntentService详细解析.md
│ │ │ ├── RecyclerView的简介.md
│ │ │ ├── Service详细解析.md
│ │ │ ├── tablayout记录.md
│ │ │ ├── test.kt
│ │ │ └── 图片缓存原理.md
│ │ ├── Android开源框架相关/
│ │ │ ├── Android当下最流行的开源框架总结.md
│ │ │ ├── Android黑科技——ButterKnifeZelezny.md
│ │ │ ├── Picasso-android-load-image-layout.md
│ │ │ ├── RxJava+retrofit2实现安卓中网络操作.md
│ │ │ ├── 一款Android的Log、Toast的库.md
│ │ │ └── 动态申请权限库:easypermissions使用与源码解析.md
│ │ ├── Android性能优化相关/
│ │ │ └── LeakCanary工作过程以及原理.md
│ │ ├── Android打包相关/
│ │ │ ├── Android发布sdk到jcenter.md
│ │ │ └── Android将library打包成jar文件或aar文件.md
│ │ ├── Android报错记录/
│ │ │ ├── Android报错-Manifest merger failed with multiple errors, see logs.md
│ │ │ └── Android报错2.md
│ │ ├── Android编译器相关/
│ │ │ ├── AndroidStudio使用教程(第一弹).md
│ │ │ ├── AndroidStudio使用教程(第七弹).md
│ │ │ ├── AndroidStudio使用教程(第三弹).md
│ │ │ ├── AndroidStudio使用教程(第二弹).md
│ │ │ ├── AndroidStudio使用教程(第五弹).md
│ │ │ ├── AndroidStudio使用教程(第六弹).md
│ │ │ └── AndroidStudio使用教程(第四弹).md
│ │ ├── Android自定义View/
│ │ │ ├── Android事件分发机制.md
│ │ │ ├── PathMeasure.md
│ │ │ ├── 三阶贝塞尔曲线.md
│ │ │ ├── 二阶贝塞尔曲线.md
│ │ │ ├── 自定义ViewGroup入门.md
│ │ │ ├── 自定义View——CameraView.md
│ │ │ ├── 自定义View——CheckView.md
│ │ │ ├── 自定义View——CircleView.md
│ │ │ ├── 自定义View——FlowLayout.md
│ │ │ ├── 自定义View——PieView.md
│ │ │ ├── 自定义View入门.md
│ │ │ └── 自定义view——sideslipListView.md
│ │ ├── Android进阶/
│ │ │ ├── AndroidStudio导入工程一直在Building的解决方案.md
│ │ │ ├── Android中的动画.md
│ │ │ ├── Android内存泄漏总结.md
│ │ │ ├── Android性能优化.md
│ │ │ ├── Android项目总结.md
│ │ │ ├── Android项目总结2.md
│ │ │ ├── Android项目总结3.md
│ │ │ ├── Handler引起的内存泄漏以及分析.md
│ │ │ ├── MVP+RxJava+Retrofit2+Dagger实战.md
│ │ │ ├── Recyclerview和Listview的异同.md
│ │ │ ├── iterm2+vim打造完美终端.md
│ │ │ ├── jvm-serializers.md
│ │ │ ├── 基于OTP算法的双向认证.md
│ │ │ ├── 检查app是否有推送权限.md
│ │ │ ├── 深入了解MVXX模式.md
│ │ │ └── 自定义RadioGroup.md
│ │ ├── Android面试相关/
│ │ │ ├── Android5.0-6.0-7.0新特性.md
│ │ │ ├── Android中常见面试题.md
│ │ │ ├── Android中弱引用与软引用.md
│ │ │ ├── Android图片三级缓存.md
│ │ │ ├── Android推送实现原理.md
│ │ │ ├── Asset目录与res目录的区别.md
│ │ │ ├── JSON的定义.md
│ │ │ ├── Java中Error和Exception.md
│ │ │ ├── ListView性能优化.md
│ │ │ ├── Service保活.md
│ │ │ ├── 如何实现Activity切换的动画.md
│ │ │ ├── 如何提高Activity启动速度.md
│ │ │ ├── 如何终止App的运行.md
│ │ │ └── 面试题.md
│ │ ├── AppPublish/
│ │ │ ├── Android应用发布.md
│ │ │ ├── Zipalign优化.md
│ │ │ └── 使用Jenkins实现自动化打包.md
│ │ ├── ArchitectureComponents/
│ │ │ ├── 1.简介(一).md
│ │ │ ├── 2.集成(二).md
│ │ │ ├── 3.Lifecycle(三).md
│ │ │ ├── 4.LiveData(四).md
│ │ │ ├── 5.ViewModel(五).md
│ │ │ ├── 6.Room(六).md
│ │ │ └── 7.PagingLibrary(七).md
│ │ ├── BasicKnowledge/
│ │ │ ├── Android入门介绍.md
│ │ │ ├── Android动画.md
│ │ │ ├── Android四大组件之ContentProvider.md
│ │ │ ├── Android四大组件之Service.md
│ │ │ ├── Android基础面试题.md
│ │ │ ├── Android编码规范.md
│ │ │ ├── Ant打包.md
│ │ │ ├── Bitmap优化.md
│ │ │ ├── Fragment专题.md
│ │ │ ├── Home键监听.md
│ │ │ ├── HttpClient执行Get和Post请求.md
│ │ │ ├── JNI_C语言基础.md
│ │ │ ├── JNI基础.md
│ │ │ ├── ListView专题.md
│ │ │ ├── Parcelable及Serializable.md
│ │ │ ├── PopupWindow细节.md
│ │ │ ├── SDK Manager无法更新的问题.md
│ │ │ ├── Scroller简介.md
│ │ │ ├── ScrollingTabs.md
│ │ │ ├── Selector使用.md
│ │ │ ├── SlidingMenu.md
│ │ │ ├── String格式化.md
│ │ │ ├── TextView跑马灯效果.md
│ │ │ ├── WebView总结.md
│ │ │ ├── Widget(窗口小部件).md
│ │ │ ├── Wifi状态监听.md
│ │ │ ├── XmlPullParser.md
│ │ │ ├── adb logcat使用简介.md
│ │ │ ├── 下拉刷新ListView.md
│ │ │ ├── 代码混淆.md
│ │ │ ├── 任务管理器(ActivityManager).md
│ │ │ ├── 修改系统组件样式.md
│ │ │ ├── 内存泄漏.md
│ │ │ ├── 多线程断点下载.md
│ │ │ ├── 安全退出应用程序.md
│ │ │ ├── 屏幕适配.md
│ │ │ ├── 应用后台唤醒后数据的刷新.md
│ │ │ ├── 应用安装.md
│ │ │ ├── 开发中Log的管理.md
│ │ │ ├── 开发中异常的处理.md
│ │ │ ├── 快捷方式工具类.md
│ │ │ ├── 手机摇晃.md
│ │ │ ├── 搜索框.md
│ │ │ ├── 数据存储.md
│ │ │ ├── 文件上传.md
│ │ │ ├── 来电号码归属地提示框.md
│ │ │ ├── 来电监听及录音.md
│ │ │ ├── 横向ListView.md
│ │ │ ├── 滑动切换Activity(GestureDetector).md
│ │ │ ├── 病毒.md
│ │ │ ├── 知识大杂烩.md
│ │ │ ├── 短信广播接收者.md
│ │ │ ├── 程序的启动、卸载和分享.md
│ │ │ ├── 竖着的Seekbar.md
│ │ │ ├── 自定义Toast.md
│ │ │ ├── 自定义控件.md
│ │ │ ├── 自定义状态栏通知.md
│ │ │ ├── 自定义背景.md
│ │ │ ├── 获取位置(LocationManager).md
│ │ │ ├── 获取应用程序缓存及一键清理.md
│ │ │ ├── 获取手机中所有安装的程序.md
│ │ │ ├── 获取手机及SD卡可用存储空间.md
│ │ │ ├── 获取联系人.md
│ │ │ ├── 读取用户logcat日志.md
│ │ │ ├── 资源文件拷贝的三种方式.md
│ │ │ ├── 超级管理员(DevicePoliceManager).md
│ │ │ ├── 锁屏以及解锁监听.md
│ │ │ ├── 零权限上传数据.md
│ │ │ ├── 音量及屏幕亮度调节.md
│ │ │ └── 黑名单挂断电话及删除电话记录.md
│ │ ├── Dagger2/
│ │ │ ├── 1.Dagger2简介(一).md
│ │ │ ├── 2.Dagger2入门demo(二).md
│ │ │ ├── 3.Dagger2入门demo扩展(三).md
│ │ │ ├── 4.Dagger2单例(四).md
│ │ │ ├── 5.Dagger2Lay和Provider(五).md
│ │ │ ├── 6.Dagger2Android示例代码(六).md
│ │ │ ├── 7.Dagger2之dagger-android(七).md
│ │ │ ├── 8.Dagger2与MVP(八).md
│ │ │ └── 9.Dagger2原理分析(九).md
│ │ ├── Git/
│ │ │ └── git详细教程.md
│ │ ├── Go/
│ │ │ └── Go的练习代码.md
│ │ ├── Gradle&Maven/
│ │ │ ├── Gradle专题.md
│ │ │ └── 发布library到Maven仓库.md
│ │ ├── IOSNote/
│ │ │ └── Ios上架app需要的图标尺寸.md
│ │ ├── IPC.md
│ │ ├── ImageLoaderLibrary/
│ │ │ ├── Glide简介(上).md
│ │ │ ├── Glide简介(下).md
│ │ │ └── 图片加载库比较.md
│ │ ├── JavaKnowledge/
│ │ │ ├── Base64加密.md
│ │ │ ├── Git简介.md
│ │ │ ├── HashMap实现原理分析.md
│ │ │ ├── Http与Https的区别.md
│ │ │ ├── JVM垃圾回收机制.md
│ │ │ ├── Java基础面试题.md
│ │ │ ├── MD5加密.md
│ │ │ ├── MVC与MVP及MVVM.md
│ │ │ ├── RMB大小写转换.md
│ │ │ ├── Top-K问题.md
│ │ │ ├── Vim使用教程.md
│ │ │ ├── hashCode与equals.md
│ │ │ ├── volatile和Synchronized区别.md
│ │ │ ├── 八种排序算法.md
│ │ │ ├── 剑指Offer(上).md
│ │ │ ├── 剑指Offer(下).md
│ │ │ ├── 动态代理.md
│ │ │ ├── 单例的最佳实现方式.md
│ │ │ ├── 原子性、可见性以及有序性.md
│ │ │ ├── 常用命令行大全.md
│ │ │ ├── 常见算法.md
│ │ │ ├── 强引用、软引用、弱引用、虚引用.md
│ │ │ ├── 数据加密及解密.md
│ │ │ ├── 数据结构.md
│ │ │ ├── 死锁.md
│ │ │ ├── 生产者消费者.md
│ │ │ ├── 算法的复杂度.md
│ │ │ ├── 线程池简介.md
│ │ │ ├── 网络请求相关内容总结.md
│ │ │ ├── 获取今后多少天后的日期.md
│ │ │ └── 设计模式.md
│ │ ├── JavaNote/
│ │ │ ├── Javaee/
│ │ │ │ └── Spring-boot入门.md
│ │ │ ├── Java相关/
│ │ │ │ ├── ArrayList、LinkedList、Vector的异同.md
│ │ │ │ ├── Des加密算法.md
│ │ │ │ ├── HashTable和HashMap的异同.md
│ │ │ │ ├── JVM类加载器.md
│ │ │ │ ├── JVM虚拟机基础知识.md
│ │ │ │ ├── Java中Error和Exception.md
│ │ │ │ ├── Java利用ExecutorService实现同步执行大量线程.md
│ │ │ │ ├── Java利用listener实现回调,即观察者模式.md
│ │ │ │ ├── Java回调的原理与实现.md
│ │ │ │ ├── Java基础知识.md
│ │ │ │ ├── Java注解的编写与Java的反射机制.md
│ │ │ │ ├── 发布jar包到Maven中央仓库.md
│ │ │ │ └── 面向对象的六大原则以及常见的十七种设计模式.md
│ │ │ └── 设计模式相关/
│ │ │ ├── 单例模式.md
│ │ │ ├── 单例模式的四种实现方式.md
│ │ │ ├── 观察者模式.md
│ │ │ └── 设计模式概括.md
│ │ ├── KotlinCourse/
│ │ │ ├── .idea/
│ │ │ │ ├── KotlinCourse.iml
│ │ │ │ ├── misc.xml
│ │ │ │ ├── modules.xml
│ │ │ │ └── workspace.xml
│ │ │ ├── Kotlin学习教程(一).md
│ │ │ ├── Kotlin学习教程(七).md
│ │ │ ├── Kotlin学习教程(三).md
│ │ │ ├── Kotlin学习教程(九).md
│ │ │ ├── Kotlin学习教程(二).md
│ │ │ ├── Kotlin学习教程(五).md
│ │ │ ├── Kotlin学习教程(八).md
│ │ │ ├── Kotlin学习教程(六).md
│ │ │ ├── Kotlin学习教程(十).md
│ │ │ └── Kotlin学习教程(四).md
│ │ ├── Kotlin相关/
│ │ │ └── Kotlin-for-android.md
│ │ ├── Linux/
│ │ │ └── Android-GitLabCi配置.md
│ │ ├── MacNote/
│ │ │ ├── Mac平台重新设置MySQL的root密码.md
│ │ │ ├── SSH原理与应用.md
│ │ │ ├── mac上常用命令.md
│ │ │ ├── mac本地生成ssh-key.md
│ │ │ ├── mac终端与服务器保持连接.md
│ │ │ ├── nodejs与npm的更新.md
│ │ │ ├── paw-for-mac.md
│ │ │ ├── 一些mac上面安装环境的指令.md
│ │ │ ├── 如何在mac上安装java1-8.md
│ │ │ └── 项目中遇到的单词.md
│ │ ├── READMENote.md
│ │ ├── ReactNative相关/
│ │ │ ├── React Native 的ES5 ES6写法对照表.md
│ │ │ ├── ReactNative入门.md
│ │ │ ├── ReactNative利用CodePush实现热更新.md
│ │ │ ├── ReactNative报错记录.md
│ │ │ ├── ReactNative调试心得.md
│ │ │ ├── Touchable系列组建讲解.md
│ │ │ └── 短信验证码倒计时控件.md
│ │ ├── RxJavaPart/
│ │ │ ├── 1.RxJava详解(一).md
│ │ │ ├── 2.RxJava详解(二).md
│ │ │ ├── 3.RxJava详解(三).md
│ │ │ ├── 4.RxJava详解之执行原理(四).md
│ │ │ ├── 5.RxJava详解之操作符执行原理(五).md
│ │ │ ├── 6.RxJava详解之线程调度原理(六).md
│ │ │ └── 7.RxJava系列全家桶.md
│ │ ├── ScriptNote/
│ │ │ ├── GitHub基础操作.md
│ │ │ ├── 一篇文章学懂Shell脚本.md
│ │ │ ├── 封装一些GitHub常用命令.md
│ │ │ └── 简单的Shell脚本.md
│ │ ├── SourceAnalysis/
│ │ │ ├── Activity启动过程.md
│ │ │ ├── Activity界面绘制过程详解.md
│ │ │ ├── Android Touch事件分发详解.md
│ │ │ ├── AsyncTask详解.md
│ │ │ ├── InstantRun详解.md
│ │ │ ├── ListView源码分析.md
│ │ │ ├── Netowork/
│ │ │ │ ├── HttpURLConnection与HttpClient.md
│ │ │ │ ├── HttpURLConnection详解.md
│ │ │ │ ├── Retrofit详解(上).md
│ │ │ │ ├── Retrofit详解(下).md
│ │ │ │ ├── Volley源码分析.md
│ │ │ │ └── volley-retrofit-okhttp之我们该如何选择网路框架.md
│ │ │ ├── VideoView源码分析.md
│ │ │ ├── View绘制过程详解.md
│ │ │ ├── butterknife源码详解.md
│ │ │ └── 自定义View详解.md
│ │ ├── Tools&Library/
│ │ │ ├── Android开发工具及类库.md
│ │ │ ├── Github个人主页绑定域名.md
│ │ │ ├── MAT内存分析.md
│ │ │ ├── Markdown学习手册.md
│ │ │ ├── 性能优化相关工具.md
│ │ │ ├── 目前流行的开发组合.md
│ │ │ └── 调试平台Flipper.md
│ │ ├── VideoDevelopment/
│ │ │ ├── Android WebRTC简介.md
│ │ │ ├── Android音视频开发.md
│ │ │ ├── DLNA简介.md
│ │ │ ├── 搭建nginx+rtmp服务器.md
│ │ │ ├── 视频播放相关内容总结.md
│ │ │ ├── 视频解码之软解与硬解.md
│ │ │ └── 音视频基础知识.md
│ │ ├── WebNote/
│ │ │ ├── MySQL相关/
│ │ │ │ ├── ERROR-1045-(28000)--Access-denied-for-user-'debian-sys-maint'@'localho.md
│ │ │ │ ├── Error--ER_TRUNCATED_WRONG_VALUE_FOR_FIELD.md
│ │ │ │ ├── Mysql导出数据库、表(有无数据).md
│ │ │ │ ├── mysql基础操作.md
│ │ │ │ └── 云服务器linux下安装MySQL.md
│ │ │ └── NodeJS相关/
│ │ │ ├── koa框架对post内容读取并解析.md
│ │ │ ├── nodejs查询数据库后将值返回前端.md
│ │ │ ├── nodejs项目在云服务器的部署.md
│ │ │ ├── test.html
│ │ │ └── 淘宝cnpm.md
│ │ ├── webRTC相关/
│ │ │ ├── WebRTC-Android源码解析.md
│ │ │ ├── WebRTC——Android入门.md
│ │ │ ├── WebRTC——AudioRenderer解析.md
│ │ │ ├── WebRTC——AudioSource、VideoSource解析.md
│ │ │ ├── WebRTC——AudioTrack-VideoTrack解析.md
│ │ │ ├── WebRTC——IceCandidate、SdpObserver、CameraSession解析.md
│ │ │ ├── WebRTC——MediaSource-java解析.md
│ │ │ ├── WebRTC——MeidaStreamTrack解析.md
│ │ │ ├── WebRTC——PeerConnection-java解析.md
│ │ │ ├── WebRTC——PeerConnectionFactory-java解析.md
│ │ │ ├── WebRTC——VideoFileRenderer解析.md
│ │ │ └── WebRTC——VideoRenderer解析.md
│ │ ├── 内存性能.md
│ │ └── 网络协议/
│ │ ├── SSH原理与应用.md
│ │ ├── 浅析Hessian协议.md
│ │ ├── 浅析RPC协议.md
│ │ ├── 浅析dubbo服务.md
│ │ └── 浅析socket.md
│ ├── interview/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── android/
│ │ │ ├── README.md
│ │ │ ├── SUMMARY.md
│ │ │ ├── activity-view-window.md
│ │ │ ├── arch.md
│ │ │ ├── binder.md
│ │ │ ├── broadcast.md
│ │ │ ├── canvas.md
│ │ │ ├── draw.md
│ │ │ ├── event.md
│ │ │ ├── eventbus.md
│ │ │ ├── handler.md
│ │ │ ├── intent.md
│ │ │ ├── keep-live.md
│ │ │ ├── launchmod.md
│ │ │ ├── lifecicle.md
│ │ │ ├── listview.md
│ │ │ ├── okhttp.md
│ │ │ ├── optimize.md
│ │ │ ├── push.md
│ │ │ ├── questions.md
│ │ │ └── version.md
│ │ ├── architecture/
│ │ │ ├── 1-cap.md
│ │ │ ├── README.md
│ │ │ ├── concurrent/
│ │ │ │ ├── 1-flow_control.md
│ │ │ │ └── README.md
│ │ │ ├── design/
│ │ │ │ ├── 1-tinyURL.md
│ │ │ │ └── README.md
│ │ │ └── distributed/
│ │ │ ├── 1-session.md
│ │ │ ├── 2-cache.md
│ │ │ ├── 3-lock.md
│ │ │ ├── 4-transaction.md
│ │ │ ├── 5-mq.md
│ │ │ ├── 6-zk.md
│ │ │ ├── 7-kafka.md
│ │ │ ├── 8-rpc.md
│ │ │ ├── 9-dubbo.md
│ │ │ └── README.md
│ │ ├── basic/
│ │ │ ├── README.md
│ │ │ ├── algo/
│ │ │ │ ├── README.md
│ │ │ │ ├── algo.md
│ │ │ │ ├── hash.md
│ │ │ │ ├── kmp.md
│ │ │ │ ├── mst.md
│ │ │ │ ├── path.md
│ │ │ │ ├── questions.md
│ │ │ │ ├── search.md
│ │ │ │ ├── skip_list.md
│ │ │ │ ├── sort.md
│ │ │ │ └── tree.md
│ │ │ ├── cryptology.md
│ │ │ ├── database/
│ │ │ │ ├── README.md
│ │ │ │ ├── concurrent_control.md
│ │ │ │ ├── index.md
│ │ │ │ ├── innodb.md
│ │ │ │ ├── join.md
│ │ │ │ ├── mysql.md
│ │ │ │ ├── questions.md
│ │ │ │ ├── redis.md
│ │ │ │ ├── sql.md
│ │ │ │ └── transaction.md
│ │ │ ├── net/
│ │ │ │ ├── README.md
│ │ │ │ ├── base_protocol.md
│ │ │ │ ├── http.md
│ │ │ │ ├── https.md
│ │ │ │ ├── ip.md
│ │ │ │ ├── osi.md
│ │ │ │ ├── questions.md
│ │ │ │ └── tcp.md
│ │ │ └── op/
│ │ │ ├── README.md
│ │ │ ├── arch.md
│ │ │ ├── concurrency.md
│ │ │ ├── device.md
│ │ │ ├── disk.md
│ │ │ ├── interrupt.md
│ │ │ ├── io.md
│ │ │ ├── linux.md
│ │ │ ├── memory.md
│ │ │ ├── os.md
│ │ │ └── questions.md
│ │ ├── fromwork/
│ │ │ ├── README.md
│ │ │ ├── mybatis/
│ │ │ │ ├── 1-question.md
│ │ │ │ ├── 2-cache.md
│ │ │ │ └── 3-proxy.md
│ │ │ └── spring/
│ │ │ ├── 1-ioc.md
│ │ │ ├── 2-design-partten.md
│ │ │ ├── 3-aop.md
│ │ │ └── README.md
│ │ └── java/
│ │ ├── 1-oop.md
│ │ ├── 17-questions.md
│ │ ├── 2-operator.md
│ │ ├── 3-exception.md
│ │ ├── 4-generics.md
│ │ ├── 5-object.md
│ │ ├── 6-StringBuilder.md
│ │ ├── 7-proxy.md
│ │ ├── README.md
│ │ ├── collection/
│ │ │ ├── 1-collection.md
│ │ │ ├── 2-HashMap.md
│ │ │ ├── 3-Concurrenthashmap.md
│ │ │ └── 4-BlockQueue.md
│ │ ├── concurrent/
│ │ │ ├── 1-thread.md
│ │ │ ├── 2-volatile.md
│ │ │ ├── 3-synchronized.md
│ │ │ ├── 4-AQS.md
│ │ │ ├── 5-threadlocal.md
│ │ │ ├── 6-interrupt.md
│ │ │ └── 7-CountDownLatch.md
│ │ ├── gc/
│ │ │ ├── 11-jvm-gc.md
│ │ │ └── 12-jvm-object-life-cycle.md
│ │ └── jvm/
│ │ ├── 1-jvm-class-load-init.md
│ │ ├── 2-jvm-class-loader.md
│ │ ├── 3-dispatcher.md
│ │ └── 4-jvm-architecture.md
│ ├── self.md
│ └── sources/
│ ├── JavaGarbageCollection.md
│ ├── JavaMemoryMode.md
│ ├── activity_onnewIntent.md
│ ├── adsl.md
│ ├── app_start_step.md
│ ├── application.md
│ ├── application_service.md
│ ├── asynctask.md
│ ├── binder.md
│ ├── butterknife.md
│ ├── davik_art.md
│ ├── design_v28.md
│ ├── eventbus.md
│ ├── fifo.md
│ ├── foreach.md
│ ├── fragment_lazy_load.md
│ ├── frame.md
│ ├── glide.md
│ ├── handle_leak.md
│ ├── hash_confict.md
│ ├── hotfix.md
│ ├── imagedownload.md
│ ├── iterationAndroidrecursion.md
│ ├── java8.md
│ ├── javaCopy.md
│ ├── javabasic.md
│ ├── javacollection.md
│ ├── killprocess_system_exit.md
│ ├── kotlin/
│ │ └── builderModel.kt
│ ├── livedata.md
│ ├── lru.md
│ ├── media_player.md
│ ├── netsafe.md
│ ├── okhttp.md
│ ├── onMeasure.md
│ ├── recyclerView_listview.md
│ ├── reference.md
│ ├── requestlayout_invalidate_postInvalidate.md
│ ├── retrofit.md
│ ├── rxjavademo.md
│ ├── seven_design_principles.md
│ ├── singleInstance.md
│ ├── synchronized_lock.md
│ ├── thread_principle.md
│ ├── tomcat_cache.java
│ ├── tomcat_lru_cache.java
│ ├── transactiontoolargeexception.md
│ ├── tree.md
│ ├── tu.md
│ ├── v4_v7_v8_v13.md
│ ├── view_root.md
│ ├── viewmodel.md
│ ├── volatile.md
│ ├── volley_algorithm.md
│ ├── wait_sleep.md
│ ├── weakHashMap.md
│ ├── workManager.md
│ └── yield_join.md
├── data/
│ └── java-recommended-books.md
├── dataStructures-algorithms/
│ ├── Backtracking-NQueens.md
│ ├── 公司真题.md
│ ├── 几道常见的子符串算法题.md
│ ├── 几道常见的链表算法题.md
│ ├── 剑指offer部分编程题.md
│ ├── 数据结构.md
│ └── 算法学习资源推荐.md
├── database/
│ ├── MySQL Index.md
│ ├── MySQL.md
│ ├── MySQL高性能优化规范建议.md
│ ├── Redis/
│ │ ├── Redis.md
│ │ ├── Redis持久化.md
│ │ ├── Redlock分布式锁.md
│ │ └── 如何做可靠的分布式锁,Redlock真的可行么.md
│ ├── 一千行MySQL命令.md
│ ├── 一条sql语句在mysql中如何执行的.md
│ └── 事务隔离级别(图文详解).md
├── essential-content-for-interview/
│ ├── BATJrealInterviewExperience/
│ │ └── 5面阿里,终获offer.md
│ ├── MostCommonJavaInterviewQuestions/
│ │ ├── 第一周(2018-8-7).md
│ │ ├── 第二周(2018-8-13).md
│ │ └── 第四周(2018-8-30).md
│ ├── PreparingForInterview/
│ │ ├── JavaInterviewLibrary.md
│ │ ├── JavaProgrammerNeedKnow.md
│ │ ├── interviewPrepare.md
│ │ ├── 如果面试官问你“你有什么问题问我吗?”时,你该如何回答.md
│ │ ├── 程序员的简历之道.md
│ │ └── 美团面试常见问题总结.md
│ ├── 手把手教你用Markdown写一份高质量的简历.md
│ ├── 简历模板.md
│ └── 面试必备之乐观锁与悲观锁.md
├── github-trending/
│ ├── 2018-12.md
│ ├── 2019-1.md
│ ├── 2019-2.md
│ ├── 2019-3.md
│ └── JavaGithubTrending.md
├── java/
│ ├── ArrayList-Grow.md
│ ├── ArrayList.md
│ ├── BIO-NIO-AIO.md
│ ├── Basis/
│ │ ├── Arrays,CollectionsCommonMethods.md
│ │ └── final、static、this、super.md
│ ├── HashMap.md
│ ├── J2EE基础知识.md
│ ├── Java IO与NIO.md
│ ├── Java基础知识.md
│ ├── Java编程规范.md
│ ├── Java虚拟机(jvm).md
│ ├── Java集合框架常见面试题总结.md
│ ├── LinkedList.md
│ ├── Multithread/
│ │ ├── AQS.md
│ │ ├── Atomic.md
│ │ ├── BATJ都爱问的多线程面试题.md
│ │ ├── ConcurrentProgramming1-并发编程基础知识.md
│ │ └── 并发容器总结.md
│ ├── What's New in JDK8/
│ │ ├── JDK8接口规范-静态、默认方法.md
│ │ ├── Java8Tutorial.md
│ │ ├── Java8教程推荐.md
│ │ ├── Lambda表达式.md
│ │ ├── README.md
│ │ ├── Stream.md
│ │ ├── 改进的类型推断.md
│ │ └── 通过反射获得方法的参数信息.md
│ ├── synchronized.md
│ ├── 可能是把Java内存区域讲的最清楚的一篇文章.md
│ ├── 多线程系列.md
│ ├── 搞定JVM垃圾回收就是这么简单.md
│ └── 这几道Java集合框架面试题几乎必问.md
├── network/
│ ├── HTTPS中的TLS.md
│ ├── 干货:计算机网络知识总结.md
│ └── 计算机网络.md
├── notes/
│ ├── Leetcode-Database 题解.md
│ ├── SQL.md
│ ├── 攻击技术.md
│ ├── 数据库系统原理.md
│ ├── 构建工具.md
│ ├── 正则表达式.md
│ ├── 计算机操作系统 - 内存管理.md
│ ├── 计算机操作系统 - 概述.md
│ ├── 计算机操作系统 - 死锁.md
│ ├── 计算机操作系统 - 目录.md
│ ├── 计算机操作系统 - 目录1.md
│ ├── 计算机操作系统 - 设备管理.md
│ ├── 计算机操作系统 - 进程管理.md
│ └── 计算机操作系统 - 链接.md
├── operating-system/
│ ├── Shell.md
│ └── 后端程序员必备的Linux基础知识.md
├── system-design/
│ ├── data-communication/
│ │ ├── dubbo.md
│ │ ├── message-queue.md
│ │ ├── rabbitmq.md
│ │ └── 数据通信(RESTful、RPC、消息队列).md
│ ├── framework/
│ │ ├── SpringBean.md
│ │ ├── SpringMVC 工作原理详解.md
│ │ ├── Spring学习与面试.md
│ │ ├── ZooKeeper.md
│ │ └── ZooKeeper数据模型和常见命令.md
│ ├── website-architecture/
│ │ ├── 8 张图读懂大型网站技术架构.md
│ │ ├── 【面试精选】关于大型网站系统架构你不得不懂的10个问题.md
│ │ └── 分布式.md
│ └── 设计模式.md
└── tools/
├── Docker-Image.md
├── Docker.md
└── Git.md
SYMBOL INDEX (14 symbols across 2 files)
FILE: docs/android/sources/tomcat_cache.java
class ConcurrentCache (line 7) | public final class ConcurrentCache<K,V> {
method ConcurrentCache (line 15) | public ConcurrentCache(int size) {
method get (line 21) | public V get(K k) {
method put (line 34) | public void put(K k, V v) {
FILE: docs/android/sources/tomcat_lru_cache.java
class LRUCache (line 5) | public class LRUCache {
class CacheNode (line 11) | class CacheNode {
method CacheNode (line 16) | CacheNode() {
method LRUCache (line 20) | public LRUCache(int i) {
method get (line 31) | public Object get(Object key) {
method put (line 46) | public void put(Object key, Object value) {
method remove (line 73) | public Object remove(Object key) {
method clear (line 90) | public void clear() {
method removeLast (line 99) | private void removeLast() {
method moveToHead (line 114) | private void moveToHead(CacheNode node) {
Condensed preview — 740 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,252K chars).
[
{
"path": "LICENSE",
"chars": 1136,
"preview": " MIT License\n\n Copyright (c) 2019 pengMaster\n\n Permission is hereby granted, free of charge, to any person obta"
},
{
"path": "README.md",
"chars": 63422,
"preview": "<h1 align=\"center\">Java Android学习/面试指南 </h1>\n\n<!--| Ⅰ | Ⅱ | Ⅲ | Ⅳ | Ⅴ | Ⅵ | Ⅶ | Ⅷ | Ⅸ | Ⅹ | Ⅹ | Ⅹ |\n| :--------: | :----"
},
{
"path": "docs/.nojekyll",
"chars": 0,
"preview": ""
},
{
"path": "docs/android/Android-Interview/.gitignore",
"chars": 352,
"preview": "# Node rules:\n## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n## Dependen"
},
{
"path": "docs/android/Android-Interview/Activity/Activity Task和Process.md",
"chars": 5200,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/Activity/App优雅退出.md",
"chars": 7739,
"preview": "### **1. RxBus优雅式**\n\n首先,在基类BaseActivity里,注册RxBus监听:\n\n```java\npublic class BaseActivity3 extends AppCompatActivity {\n "
},
{
"path": "docs/android/Android-Interview/Activity/README.md",
"chars": 407,
"preview": "## Activity相关面试题\n\n- [onSaveInstanceState源码内核分析](onSaveInstanceState源码内核分析.md)\n- [深刻剖析activity启动模式-1](深刻剖析activity启动模式-1."
},
{
"path": "docs/android/Android-Interview/Activity/onCreate源码分析.md",
"chars": 1972,
"preview": "Activity扮演了一个界面展示的角色,堪称四大组件之首,onCreate是Activity的执行入口,都不知道入口到底干了嘛,还学什么android,所以本文会从源码的角度对其进行分析。\n\n熟悉源码的会发现,真正启动Activity的实"
},
{
"path": "docs/android/Android-Interview/Activity/onSaveInstanceState源码内核分析.md",
"chars": 8912,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/Activity/为什么service里面startActivity抛异常.md",
"chars": 3955,
"preview": "**Android面试题-源码分析为什么service里面startActivity抛异常?activity不会**\n\n我们有时候需要在service里面启动activity,但是会发现报如下异常:\n\n. http://www.cloudchou.com/android/post-788.html\n\n## 概述\n\nAndroid中启动某个Acti"
},
{
"path": "docs/android/Android-Interview/Activity/深刻剖析activity启动模式-1.md",
"chars": 16783,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/Activity/深刻剖析activity启动模式-2.md",
"chars": 28152,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/Activity/深刻剖析activity启动模式-3.md",
"chars": 12606,
"preview": "前面介绍了通过launchMode设置Activity的启动模式。本章接着介绍Activity的启动模式相关内容,讲解的内容是Intent与启动模式相关的Flag,以及android:taskAffinity的属性。\n\n### **Inte"
},
{
"path": "docs/android/Android-Interview/Android/Android基础面试核心内容.md",
"chars": 45574,
"preview": "## Android基本常识\n\n### 1. 写10个简单的linux命令\n\n| 命令 | 作用 |\n| :------- | :--------------------- |\n| mkd"
},
{
"path": "docs/android/Android-Interview/Android/Android视频教程.md",
"chars": 557,
"preview": "## Android视频教程\n\n- 零基础入门Android语法与界面 \n- Kotlin系统入门与进阶\n- 从Java到Kotlin系列精讲\n- Kotlin打造完整电商APP 模块化+MVP+主流框架\n- Android强化:服务与通信"
},
{
"path": "docs/android/Android-Interview/Android/Android面试精华题目总结.md",
"chars": 6117,
"preview": "> 原文链接:http://blog.csdn.net/lmj623565791/article/details/24015867/\n\n下面的题目都是楼主在[Android](http://lib.csdn.net/base/android"
},
{
"path": "docs/android/Android-Interview/Android/Android面试重点.md",
"chars": 10126,
"preview": "## Imageloader\n\n### 常用的图片处理框架\n\nFresco 正在实现了三级缓存,2级内存缓存,一级本地缓存、Glide、Picasso、UIL-ImageLoader\n\n### 图片占用内存\n\n大小 = 每个像素占用的字节数"
},
{
"path": "docs/android/Android-Interview/Android/Android面试题-1.md",
"chars": 1866,
"preview": "\n\n\n\n\n\n\n\n### 整个面试题视频如下(持续更新中):\n\n#### 与IPC机制相关面试题\n\n- ["
},
{
"path": "docs/android/Android-Interview/Android/Android面试题-2.md",
"chars": 9194,
"preview": "---\ntypora-copy-images-to: img\n---\n\n## Android启动流程\n\n  \n\n\n\n"
},
{
"path": "docs/android/Android-Interview/Android/Android高级面试10大开源框架源码解析.md",
"chars": 7138,
"preview": "## Android高级面试,10大开源框架源码解析\n\n编程最好的学习方法是阅读顶尖工程师的源码!本课程将带你深度剖析Android主流开源框架的源码,让你全面掌握框架的使用场景、内部机制、构造原理、核心类、架构与设计思想等,提升你的代码阅"
},
{
"path": "docs/android/Android-Interview/Android/BAT大咖助力全面升级Android面试.md",
"chars": 2219,
"preview": "## BAT大咖助力,全面升级Android面试\n\n安卓面试全新升级课程,已经帮助很多同学在短时间内拿到了满意的offer,作为Android开发求职路上快速赢取满意offer的必备课程,不管你是什么级别的工程师,都可以通过这门课程的学习,"
},
{
"path": "docs/android/Android-Interview/Android/README.md",
"chars": 212,
"preview": "## Android面试题\n\n- [Android基础面试核心内容](Android基础面试核心内容.md)\n- [Android面试精华题目总结](Android面试精华题目总结.md)\n- [Android面试题-1](Android面"
},
{
"path": "docs/android/Android-Interview/Android/平台架构.md",
"chars": 3236,
"preview": "Android 是一种基于 Linux 的开放源代码软件栈,为广泛的设备和机型而创建。下图所示为 Android 平台的主要组件。\n\n\n\n## Linux 内核\n\n"
},
{
"path": "docs/android/Android-Interview/Android/接口安全.md",
"chars": 5342,
"preview": "保证接口安全一般分为两种,一个是防数据篡改,一个是防数据泄漏,防篡改使用摘要验证,防泄漏使用加密\n\n\n\n## token\n\ntoken=5位随机数+时间戳\n\naesEnctrypt(token)\n\n(1)验证时间和服务器时间不能超过3分。\n"
},
{
"path": "docs/android/Android-Interview/HR/README.md",
"chars": 93,
"preview": "## 人事面\n\n- [人事面试宝典一之自我介绍](人事面试宝典一之自我介绍.md)\n- [人事面试宝典二之离职](人事面试宝典二之离职.md)\n- [人事面试宝典](人事面试宝典.md)"
},
{
"path": "docs/android/Android-Interview/HR/人事面试宝典.md",
"chars": 15724,
"preview": "## [面试题-史上最全人事面试宝典](http://www.jianshu.com/p/d61b553ff8c9)\n\n### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc"
},
{
"path": "docs/android/Android-Interview/HR/人事面试宝典一之自我介绍.md",
"chars": 3024,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/HR/人事面试宝典二之离职.md",
"chars": 2413,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/Java/115个Java面试题及回答.md",
"chars": 288,
"preview": "## 115个Java面试题及回答\n\n简介 在本教程中,我们将讨论在Java面试中,用人单位用来测试应聘者Java以及面向对象的能力的面试题目.以下章节我们将按照以下结构讨论面试问题,面向对象编程及其特性,Java及其特性的一般问题,集合,"
},
{
"path": "docs/android/Android-Interview/Java/66道经典的Java基础面试题集锦.md",
"chars": 8049,
"preview": "### 问题:如果main方法被声明为private会怎样?\n\n答案:能正常编译,但运行的时候会提示”main方法不是public的”。\n\n### 问题:Java里的传引用和传值的区别是什么?\n\n答案:传引用是指传递的是地址而不是值本身,传"
},
{
"path": "docs/android/Android-Interview/Java/J2SE基础面试核心内容.md",
"chars": 8783,
"preview": "有人可能会问对于我们学Android的同学来讲,面试还会问Java基础吗?答案是会的,但是不会太多,因此我给了两颗星的重要程度。一般笔试的时候出现java基础题的概率比较大,口头面试的时候比较少,比如自己在面试的时候一些对基础知识比较看重的"
},
{
"path": "docs/android/Android-Interview/Java/J2SE高级面试核心内容.md",
"chars": 12061,
"preview": "# 1. Java中的反射\n\n## 1.1 说说你对Java中反射的理解\n\nJava中的反射首先是能够获取到Java中要反射类的字节码,获取字节码有三种方法\n\n- Class.forName(className)\n- 类名.class\n- "
},
{
"path": "docs/android/Android-Interview/Java/Java面试题-1.md",
"chars": 1241,
"preview": "### 1. JRE与JDK的区别?\n\nJRE:java运行时的环境,JDK:包含JRE并且可以查看源码\n\n### 2. Java中的数据类型都有哪些?\n\n分别是8种基本数据类型:byte、short、int、long、float、doub"
},
{
"path": "docs/android/Android-Interview/Java/Java面试题-2.md",
"chars": 7618,
"preview": "**1.Java泛型中的泛型参数能不能是基本类型,比如ArrayList<T>中的T可不可以是int,为什么?ArrayList<String>中可不可以插入数字,如果可以,请用代码示例,如果不可以,请说明原因?**\n\n答:不能,泛型要求能"
},
{
"path": "docs/android/Android-Interview/Java/Java高级软件工程师面试考纲.md",
"chars": 2798,
"preview": "如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构、算法、网络、操作系统等知识。因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希"
},
{
"path": "docs/android/Android-Interview/Java/README.md",
"chars": 299,
"preview": "## Java面试题\n\n- [深拷贝浅拷贝](深拷贝浅拷贝.md)\n- [数据库求差](数据库求差.md)\n- [Java面试题-1](Java面试题-1.md)\n- [Java面试题-2](Java面试题-2.md)\n- [Java高级软"
},
{
"path": "docs/android/Android-Interview/Java/数据库求差.md",
"chars": 1558,
"preview": "今日,有同学跟我说他在最近在面试的时候,面试官问了他一个很简单的问题,结果他一脸懵逼,他可是有过一年开发经验的,怎么可能会在面试的时候马失前蹄了呢?大家来看下他的问题你们会不会。\n\n\n2. [2016Android某公司面试题](http://blog.csdn.net/jdsj"
},
{
"path": "docs/android/Android-Interview/SUMMARY.md",
"chars": 4280,
"preview": "# Summary\n\n* [前言](README.md)\n* [Android视频教程](Android/Android视频教程.md)\n* [BAT大咖助力,全面升级Android面试](Android/BAT大咖助力全面升级Androi"
},
{
"path": "docs/android/Android-Interview/Service/Android面试题-Service.md",
"chars": 490,
"preview": "**Android面试题-Service是否在main thread中执行, service里面是否能执行耗时的操作?**\n\nService不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Serv"
},
{
"path": "docs/android/Android-Interview/Service/Android面试题-Service不死之身.md",
"chars": 2655,
"preview": "### 1. 在onStartCommand方法中将flag设置为START_STICKY;\n\n```\nreturn Service.START_STICKY;\n```\n\n### 2. 在xml中设置了android:priority\n\n`"
},
{
"path": "docs/android/Android-Interview/Service/IntentService源码分析.md",
"chars": 5686,
"preview": "IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentServ"
},
{
"path": "docs/android/Android-Interview/Service/README.md",
"chars": 188,
"preview": "## Service相关面试题\n\n- [IntentService源码分析](IntentService源码分析.md)\n- [Service是否在main thread中执行, service里面是否能执行耗时的操作?](Android面"
},
{
"path": "docs/android/Android-Interview/book.json",
"chars": 188,
"preview": "{\n \"author\": \"JackChan\",\n \"description\": \"Android面试宝典\",\n \"gitbook\": \"3.2.3\",\n \"language\": \"zh-hans\",\n \"ti"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/Context原理分析.md",
"chars": 5803,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/README.md",
"chars": 294,
"preview": "## 与开发相关面试题\n\n- [迭代开发的时候如何向前兼容新旧接口?](迭代开发的时候如何向前兼容新旧接口?.md)\n- [手把手教你如何解决as jar包冲突](手把手教你如何解决as jar包冲突.md)\n- [Context原理分析]"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/ViewPager和Fragment使用过程中会遇到哪些问题.md",
"chars": 1232,
"preview": "**ViewPager和Fragment使用过程中会遇到哪些问题**\n\n### 1. 适配器的选择\n\n使用ViewPager加载多个Fragment时,我一般选择FragmentPagerAdapter。\n需要大家注意:\nFragmentP"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/手把手教你如何解决as jar包冲突.md",
"chars": 2986,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/机型适配之痛.md",
"chars": 15727,
"preview": "由于开源三方定制系统较多,请大家详细描述场景、机型及解决方案,方便其他朋友参考\n\n[问答]-Android开发中有哪些兼容性问题?都是怎么解决的?\n[问答] 你在工作中遇到的最复杂的问题或者bug是什么?你是怎么搞定的?\n\n#### **华"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/终极解决ViewPager.setCurrentItem中间页面过多解决方案.md",
"chars": 5940,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/解决字体适配.md",
"chars": 1792,
"preview": "## [Android面试题-解决字体适配](http://www.jianshu.com/p/33d499170e25)\n\n\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/开发遇到的问题/迭代开发的时候如何向前兼容新旧接口?.md",
"chars": 2331,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/性能优化/Android应用UI性能分析.md",
"chars": 4196,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/性能优化/App应用启动分析与优化.md",
"chars": 6990,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/性能优化/README.md",
"chars": 229,
"preview": "## 与性能优化相关面试题\n\n- [内存泄漏和内存溢出区别](与性能优化相关试题一.md)\n- [UI优化和线程池实现原理](与性能优化相关试题二.md)\n- [代码优化](与性能优化相关试题三.md)\n- [Android应用UI性能分析"
},
{
"path": "docs/android/Android-Interview/性能优化/与IPC机制相关面试题.md",
"chars": 4843,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/性能优化/与性能优化相关试题一.md",
"chars": 3326,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/性能优化/与性能优化相关试题三.md",
"chars": 3191,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/性能优化/与性能优化相关试题二.md",
"chars": 5528,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/性能优化/内存泄漏监测.md",
"chars": 3222,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/源码分析/Android源码编译实现静默安装和静默偷拍.md",
"chars": 9456,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://blog.csdn.net/mwq384807683/article/details/71305969)\n- [注解框架实现原理](http://blog.csdn."
},
{
"path": "docs/android/Android-Interview/源码分析/README.md",
"chars": 157,
"preview": "## 源码分析相关面试题\n\n- [Volley源码剖析](Volley源码剖析.md)\n- [注解框架内部实现原理](注解框架内部实现原理.md)\n- [okhttp内核剖析](okhttp内核剖析.md)\n- [Android源码编译实现"
},
{
"path": "docs/android/Android-Interview/源码分析/Volley源码剖析.md",
"chars": 14629,
"preview": "今天就带大家一层层剥光Volley这位懵懂无知少女(14年出生,应该算无知少女)的外衣,带大家轻轻抚摸Volley每一寸肌肤,进入Volley的身体,为达到完美效果,开头录有激情小视频,观看时请自备纸巾,各位现在需要做的就是搬一把椅子,打开"
},
{
"path": "docs/android/Android-Interview/源码分析/okhttp内核剖析.md",
"chars": 23704,
"preview": "okhttp源码特别特别复杂,类涉及较多,导致本文非常长,我相信没有几个人能把本文看完,所以特意录制了跟文章同步的视频。\n\n### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3"
},
{
"path": "docs/android/Android-Interview/源码分析/注解框架内部实现原理.md",
"chars": 6799,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/登陆注册/Oauth的实现原理.md",
"chars": 2722,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/登陆注册/README.md",
"chars": 106,
"preview": "## 与登录相关面试题\n\n- [Oauth的实现原理](Oauth的实现原理.md)\n- [Token的实际意义](token的实际意义.md)\n- [微信扫码登录内部实现原理](微信扫码登录内部实现原理.md)"
},
{
"path": "docs/android/Android-Interview/登陆注册/Token的实际意义.md",
"chars": 2962,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/登陆注册/微信扫码登录内部实现原理.md",
"chars": 3426,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/经验分享/2016年4月某公司面试题及面试流程.md",
"chars": 2108,
"preview": "## 2016年4月某公司面试题及面试流程\n\n### **1. 静态内部类、内部类、匿名内部类,为什么内部类会持有外部类的引用?持有的引用是this?还是其它?**\n\n- 静态内部类:使用static修饰的内部类\n- 内部类:就是在某个类的"
},
{
"path": "docs/android/Android-Interview/经验分享/2017届实习生招聘面经.md",
"chars": 4502,
"preview": "[2017届实习生招聘面经(今日头条,腾讯,阿里,360)](http://www.jianshu.com/p/12654b063553)\n\n# 1. 阿里内推\n\n在三月的某一天,当我还沉浸在代码世界的时候,突然一声铃声响,拿起手机一看,杭"
},
{
"path": "docs/android/Android-Interview/经验分享/Andorid-15k+的面试题.md",
"chars": 157017,
"preview": "andorid开发也做了3年有余了,也面试很多加企业,借此机会分享一下,我们中遇到过的问题以及解决方案吧,希望能够对正在找工作的andoird程序员有一定的帮助。特别献上整理过的50道面试题目\n\n## 1.listView的优化方式\n\n- "
},
{
"path": "docs/android/Android-Interview/经验分享/Android 暑期实习生面试经验谈.md",
"chars": 6188,
"preview": "作为一个双非渣硕,历经两个月的时间,面试了大大小小公司的 Android 实习生岗位,最近终于结束了面试状态,决定好好把面试问题以及相关经验整理下来,顺便附带自己的学习经验与准备过程,攒攒人品,为秋招再战。\n\n## 前言\n\n2016 年开始"
},
{
"path": "docs/android/Android-Interview/经验分享/Android 曲折的求职之路.md",
"chars": 5584,
"preview": "## 个人近况\n\n[本人博客](http://mikeejy.github.io/) ,先说下博主最近近况,今年 2 月份从信和财富出来,去了一家创业公司结果不堪 996 的压榨,5 月底毅然离职没想到目前市场这么萧条,怪自己太作,有好的机"
},
{
"path": "docs/android/Android-Interview/经验分享/BAT无线工程师面试流程详细解析.md",
"chars": 7268,
"preview": "原文出处:http://www.jianshu.com/users/3bbb1ddf4fd5\n\n简书Tamic ,http://www.jianshu.com/p/f0d2ed1254a9\n\n\n- [我为什么离开锤子科技?](我为什么离开锤子科技?.md)\n- [扫清Android面试障碍](扫清Android面试障碍.md)\n- [史上最全 Android"
},
{
"path": "docs/android/Android-Interview/经验分享/一个五年Android开发者百度、阿里、聚美、映客的面试心经.md",
"chars": 17652,
"preview": "### 花絮\n\n本文为完整版,加了一些彩蛋哦!文末有面试和必备的技能点总结。\n\n> 也许会有人感叹某些人的运气比较好,但是他们不曾知道对方吃过多少苦,受过多少委屈。某些时候就是需要我们用心去发现突破点,然后顺势而上,抓住机遇,那么你将会走向"
},
{
"path": "docs/android/Android-Interview/经验分享/一个程序员的血泪史.md",
"chars": 3113,
"preview": "我的第一份工作,是某某电力.\n\n求职过程很有意思:有一天辅导员有家国企严招聘,说都去看看;结果去了发现只有几个人在,一位大姐说:人都到齐了吗?那就开始吧.我介绍一下我们公司,你们愿意来的话,就填个表. 完全没有面试….就算是有了第一份工作."
},
{
"path": "docs/android/Android-Interview/经验分享/互联网公司面试经验总结.md",
"chars": 6283,
"preview": "这是一位攻城狮面试了近十家互联网公司总结下来的经验之谈:\n\n我现在主要的方向是Java服务端开发,把遇到的问题和大家分享一下,也谈谈关于技术人员如何有方向的提高自己,做到有的放矢。\n\n面试遇到的问题\n\n## 1. 百度\n\n百度最近真是炙手可"
},
{
"path": "docs/android/Android-Interview/经验分享/互联网巨头BAT3内部员工的真实状况.md",
"chars": 2217,
"preview": "【导读】在中国互联网竞争加剧,让巨头们对用户的竞争很激烈,对人才的竞争更激烈。中国4家市值超过100亿美元的互联网巨头公司BAT3,对待员工的方式,以及组织架构都各有不同,因此造成了各自风格鲜明的企业文化,究竟巨头内部员工生活工作状态如何,"
},
{
"path": "docs/android/Android-Interview/经验分享/史上最全 Android 面试资料集合.md",
"chars": 3173,
"preview": "\n\n最近看到很多人都在找工作, 而且很多人都感觉今年找工作比去年难很多, 竞争力也增加不少, 因此激发我整理这份资料, 希望能帮到正在找或者准备找工作的童鞋们.\n\n首先我们能否获得一个面试机会, 那肯定是从简历"
},
{
"path": "docs/android/Android-Interview/经验分享/国内一线互联网公司内部面试题库.md",
"chars": 45476,
"preview": "## 国内一线互联网公司内部面试题库\n\n以下面试题来自于百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐内部题库\n\n熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。\n\nGitHub:https://github.com/Ja"
},
{
"path": "docs/android/Android-Interview/经验分享/工作三年后,我选择离开腾讯.md",
"chars": 5264,
"preview": "> 来源:微信公众号「LJ 说」,id:「LjNotes」。\n\n“你居然要从腾讯离职了!?”\n\n这是身边朋友得知我要离开后的反应,似乎大家都难以理解这样的决定。\n\n从行业环境来看,中国互联网正处于一派繁荣之境;从公司形势来看,也正要准备大刀"
},
{
"path": "docs/android/Android-Interview/经验分享/我为什么离开锤子科技?.md",
"chars": 4479,
"preview": "我在2015年3月入职锤子科技,最近几天离职,现在特别想把这不到两年的时间里的经历和我对这家公司的想法写下来。最近一段时间公司发生了大面积的裁员,但是我并不属于这一次陆陆续续的裁员的范围,而是自己提出离职的,最后发生了一些不愉快的事情,后面"
},
{
"path": "docs/android/Android-Interview/经验分享/我为什么要离开华为?.md",
"chars": 2462,
"preview": "> 原文链接:微信公众号[小李成长笔记]\n\n到 9 月中旬,我在华为工作就满 6 年了。\n\n同事听说我要离职,都很诧异。干的好好的啊,怎么突然说要走?\n\n是啊,在现在的部门这么久了,人和事都很熟了,偶然有些小摩擦,都可以理解和接受。那为什么"
},
{
"path": "docs/android/Android-Interview/经验分享/扫清Android面试障碍.md",
"chars": 11534,
"preview": "## [扫清Android面试障碍](http://chaojimiaomiao.github.io/2016/05/08/%E6%89%AB%E6%B8%85Android%E9%9D%A2%E8%AF%95%E9%9A%9C%E7%A2"
},
{
"path": "docs/android/Android-Interview/经验分享/技术硬碰硬—阳哥带你玩转上海Android招聘市场.md",
"chars": 30936,
"preview": "# 1. 挑战公司No.1:上海创梯信息科技有限公司\n\n公司地址:上海杨浦区昆明路1209号尚凯大厦副楼504室\n\n面试时间:5月12日 10:00 AM.\n面试结果:顺利砍下Android技术总监,15K offer\n面试过程:\n10:0"
},
{
"path": "docs/android/Android-Interview/经验分享/杭州找 Android 工作的点点滴滴.md",
"chars": 4531,
"preview": "## 写在前面的话\n\n我从 14 年毕业到现在一直待一个三线城市,就用 C 市 代替吧。地方很小,适合居住,但不适合 it 开发,城市很小、圈子很小,it 不发达,想要在 it 上面有出路的还是得去北上广深大城市。我在这个城市呆了三年左右由"
},
{
"path": "docs/android/Android-Interview/经验分享/给培训班出来的一点不成熟的小建议.md",
"chars": 2307,
"preview": "## 那些IT培训出来的Android工程师,希望你面试时涨点记性\n\n这几天,公司在前程无忧上发布了招聘 Andriod 工程师广告。不到 3 个小时, hr 就抱怨说投递 Andriod 工程师的简历已经多达 300 份了。不得已将 An"
},
{
"path": "docs/android/Android-Interview/经验分享/腾讯公司程序员面试题及答案详解.md",
"chars": 2990,
"preview": "今天给大家带来的是腾讯的面试题,觉得有用的亲,赏个脸,轻点上面蓝色黑马程序员几个字关注我吧!\n\n**1、腾讯笔试题:const的含义及实现机制const的含义及实现机制,比如:const int i,是怎么做到i只可读的?**\n\nconst"
},
{
"path": "docs/android/Android-Interview/经验分享/阿里+百度+CVTE面经合集.md",
"chars": 6761,
"preview": "早上11点,刚刚收到阿里的offer,也算是给自己三个月的春招画上了一个还算圆满的句号。 \n\n先介绍一下本人的基本情况:陕西普通一本非计算机专业大三学生,非985211。主要技能C/C++/Java/数据结构/算法。 \n\n这三个月的经历,首"
},
{
"path": "docs/android/Android-Interview/经验分享/面试心得与总结:BAT、网易、蘑菇街 .md",
"chars": 12961,
"preview": "之前实习的时候就想着写一篇面经,后来忙就给忘了,现在找完工作了,也是该静下心总结一下走过的路程了,我全盘托出,奉上这篇诚意之作,希望能给未来找工作的人一点指引和总结,也希望能使大家少走点弯路,如果能耐心读完,相信对你会找到你需要的东西。\n\n"
},
{
"path": "docs/android/Android-Interview/网络编程/Android客户端和服务端如何使用Token和Session.md",
"chars": 1465,
"preview": "对于初学者来说,对Token和Session的使用难免会限于困境,开发过程中知道有这个东西,但却不知道为什么要用他?更不知道其原理,今天我就带大家一起分析分析这东西。\n\n## 我们先解释一下他的含义:\n\n1、Token的引入:Token是在"
},
{
"path": "docs/android/Android-Interview/网络编程/README.md",
"chars": 182,
"preview": "## 网络编程\n\n- [Android客户端和服务端如何使用Token和Session](Android客户端和服务端如何使用Token和Session.md)\n- [推送原理](推送原理.md)\n- [阐述一下对XMPP协议理解以及优缺点"
},
{
"path": "docs/android/Android-Interview/网络编程/推送原理.md",
"chars": 1927,
"preview": "# 极光推送技术原理:移动无线网络长连接\n\n## 移动互联网应用现状\n\n因为手机平台本身、电量、网络流量的限制,移动互联网应用在设计上跟传统 PC 上的应用很大不一样,需要根据手机本身的特点,尽量的节省电量和流量,同时又要尽可能的保证数据能"
},
{
"path": "docs/android/Android-Interview/网络编程/简单阐述一下及时推送原理?.md",
"chars": 3019,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/网络编程/阐述一下对XMPP协议理解以及优缺点?.md",
"chars": 4383,
"preview": "### 源码分析相关面试题\n\n- [Volley源码分析](http://www.jianshu.com/p/ec3dc92df581)\n- [注解框架实现原理](http://www.jianshu.com/p/20da6d6389e1)"
},
{
"path": "docs/android/Android-Interview/面试技巧/README.md",
"chars": 117,
"preview": "## 面试技巧\n\n- [程序员面试宝典](程序员面试宝典.md)\n- [罗永浩新东方万字求职信](/罗永浩新东方万字求职信.md)\n- [我在面试中最喜欢问开发者的问题,和回答思路](我在面试中最喜欢问开发者的问题,和回答思路.md)"
},
{
"path": "docs/android/Android-Interview/面试技巧/我在面试中最喜欢问开发者的问题,和回答思路.md",
"chars": 2158,
"preview": "本文作者是 Zach Mathew,他是 FreshBooks 的经理。\n\n我面试过很多人,大部分是开发者,部分是产品经理,有时候会面试主管或者副总监。但不管是面试什么级别和什么工种的应聘者,我都会在过程中对他们提出一个相同的要求: 现在,"
},
{
"path": "docs/android/Android-Interview/面试技巧/程序员面试宝典.md",
"chars": 7293,
"preview": "行业资深大牛,在实际面试百八十号的程序员工作中,深度总结什么样子的人,比较容易拿到offer!绝对值得一看哦\n\n## 1. 题要做满\n\n一般来说,程序员面试都会先由HR给一张面试题。面试题一般包含:逻辑题、代码规范、数据库理论、简单算法、高"
},
{
"path": "docs/android/Android-Interview/面试技巧/罗永浩新东方万字求职信.md",
"chars": 6968,
"preview": "俞校长您好:\n\n 我先对照一下新东方最新的招聘要求:\n\n 1、有很强的英语水平,英语发音标准\n\n 英语水平还好,发音非常标准,我得承认比王强老师的发音差一点。很多发音恐怖的人(宋昊、陈圣元之流)也可以是新东方的品牌教师,我不知道为什么"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/1.热修复实现(一).md",
"chars": 26097,
"preview": "\n热修复实现(一)\n===\n\n\n现在的热修复方案已经有很多了,例如`alibaba`的[dexposed](https://github.com/alibaba/dexposed)、[AndFix](https://github.com/a"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/2.热修复实现(二).md",
"chars": 3535,
"preview": "\n热修复实现(一)\n===\n\n之前也分析过`InstantRun`的源码,前面也写了一篇热修复实现原理的文章。\n\nBut,最近遇到困难了,所在项目要做插件化,同事在开发过程中遇到了一个在5.0以下手机崩溃的问题,想着一起找找原因修复下。\n但"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/3.热修复_addAssetPath不同版本区别原因(三).md",
"chars": 15103,
"preview": "在做热修复功能时Java层通过反射调用addAssetPath在Android5.0及以上系统没有问题,在Android 4.x版本找不到资源。 \n\naddAssetPath方法: \n```java\n/**\n * Add an addi"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/ART与Dalvik.md",
"chars": 1305,
"preview": "ART与Dalvik\n===\n\n\n\nDalvik\n---\n\n`Dalvik`是`Google`公司自己设计用于`Android`平台的`Java`虚拟机。它可以支持已转换为`.dex`(即`Dalvik Executable`)格式的`Ja"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Android WorkManager.md",
"chars": 5499,
"preview": "Android WorkManager\n===\n\n谷歌在今年的`Google I/O`上宣布了一项非常令人兴奋的功能,该功能允许开发人员执行传统上需要详细了解各种API级别和可用于这些API的后台任务库的后台任务(简单点说就是”管理一些要在"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Android6.0权限系统.md",
"chars": 23373,
"preview": "Android6.0权限系统\n===\n\n`Android`权限系统是一个非常重要的安全问题,因为它只有在安装时会询问一次。一旦软件本安装之后,应用程序可以在用户毫不知情的情况下使用这些权限来获取所有的内容。 \n\n很多坏蛋会通过这个安"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Android卸载反馈.md",
"chars": 3964,
"preview": "Android卸载反馈\n===\n\n最初记得是在360安全卫士中出现的,在手机上卸载他的应用之后浏览器就会弹出一个反馈页面,让用户进行反馈,感觉这种功能对于产品改进特别有帮助。\n但是仔细一想该怎么去实现却犯愁了,最开始想这也简单啊,不就是监听"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Android启动模式详解.md",
"chars": 3594,
"preview": "Android启动模式详解\n===\n\n- `standard` \n 默认模式。在该模式下,`Activity`可以拥有多个实例,并且这些实例既可以位于同一个`task`,也可以位于不同的`task`。每次都会新创建。\n- `si"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Android开发不申请权限来使用对应功能.md",
"chars": 2128,
"preview": "Android开发不申请权限来使用对应功能\n===\n\n从用户角度来说很难获取到正确的`android`权限。通常你只需要做一些很基础的事(例如编辑一个联系人)但实际你申请的权限却远远比这更强大(例如可以获取到所有的联系人明细等)。\n\n这样能"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Android开发中的MVP模式详解.md",
"chars": 18756,
"preview": "Android开发中的MVP模式详解\n===\n\n[MVC、MVP、MVVM介绍][1]\n\n {\n @Override\n public void handle"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Library项目中资源id使用case时报错.md",
"chars": 2067,
"preview": "Library项目中资源id使用case时报错\n===\n\n在平时开发的过程中对一些常量的判断,都是使用`switch case`语句,因为`switch case`比`if else`的效率稍高。 \n但是也遇到了问题,就是在`lib"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/Mac下配置adb及Android命令.md",
"chars": 798,
"preview": "Mac下配置adb及Android命令\n===\n\n带着欣喜若狂的心情,买了一个`Mac`本,刚拿到它的时候感觉真的是一件艺术品,哈哈。废话不多说,里面配置`Android`开发环境。\n\n1. 找到`android sdk`的本地路径,\n "
},
{
"path": "docs/android/AndroidNote/AdavancedPart/MaterialDesign使用.md",
"chars": 19256,
"preview": "MaterialDesign使用\n===\n\n- `Material Design`是`Google`在`2014`年的`I/O`大会上推出的全新设计语言。 \n- `Material Design"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/RecyclerView专题.md",
"chars": 21904,
"preview": "RecyclerView专题\n===\n\n### 简介\n\n`RecyclerView`是`Android 5.0`提供的新控件,已经用了很长时间了,但是一直没有时间去仔细的梳理一下。现在项目不太紧,决定来整理下。\n\n官方文档中是这样介绍的: "
},
{
"path": "docs/android/AndroidNote/AdavancedPart/如何让Service常驻内存.md",
"chars": 821,
"preview": "如何让Service常驻内存\n===\n\n我非常鄙视这种行文,一个公司应该想到如何把产品做的更完善,而不是用这些技术来损害用户的利益,来获取自己肮脏的所谓的功能。\n\n- `Service`设置成`START_STICKY`,`kill`后会被"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/屏幕适配之百分比方案详解.md",
"chars": 22431,
"preview": "屏幕适配之百分比方案详解\n===\n\n`Android`设备碎片化十分严重,在开发过程中的适配工作也非常很繁琐,有关屏幕适配的介绍请看之前的文章[屏幕适配](https://github.com/CharonChui/AndroidNote/"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/布局优化.md",
"chars": 4759,
"preview": "布局优化\n===\n\n- 去除不必要的嵌套和节点\n 这是最基本的一条,但也是最不好做到的一条,往往不注意的时候难免会一些嵌套等。 \n\t- 首次不需要的节点设置为`GONE`或使用`ViewStud`. \n\t- 使用`R"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/性能优化.md",
"chars": 1297,
"preview": "性能优化\n===\n\n代码优化原则: \n---\n\n- 时间换时间:\n\t如禁用电脑的一些开机启动项,通过减少这些没必要的启动项的时间从而节省开机时间\n\t如网站界面上数据的分批获取,`AJAX`技术\n- 时间换空间:\n\t如拷贝文件时ne"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/注解使用.md",
"chars": 52875,
"preview": "注解使用\n===\n\n### 简介\n\n> Annotations, a form of metadata, provide data about a program that is not part of the program itself"
},
{
"path": "docs/android/AndroidNote/AdavancedPart/通过Hardware Layer提高动画性能.md",
"chars": 5314,
"preview": "通过Hardware Layer提高动画性能\n===\n\n项目中越来越多的动画,越来越多的效果导致了应用性能越来越低。该如何提升。 \n\n### 简介 \n\n在`View`播放动画的过程中每一帧都需要被重绘。如果使用`view layers`"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/Android Studio你可能不知道的操作.md",
"chars": 2802,
"preview": "Android Studio你可能不知道的操作\n===\n\n今天看在`Youtube`看视频,看到`Reto Meier`在讲解`Studio`,\n一查才知道他现在是`Studio`的开发人员。\n想起刚开始学`Android`时买的他写的书`"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio中进行ndk开发.md",
"chars": 2981,
"preview": "AndroidStudio中进行ndk开发\n===\n\n- 创建工程,声明`native`方法。 \n\t```java\n\tprivate native void startDaemon(String serviceN"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio使用教程(第一弹).md",
"chars": 11794,
"preview": "AndroidStudio使用教程(第一弹)\n===\n\n`Android Studio`是一套面世不久的`IDE`(即集成开发环境),免费向谷歌及`Android`的开发人员发放。`Android Studio`以`IntelliJ IDE"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio使用教程(第七弹).md",
"chars": 13226,
"preview": "AndroidStudio使用教程(第七弹)\n===\n\n本文讲解一下`Gradle`的应用,大家都知道`Gradle`使用起来非常方便,那他究竟方便在哪里? \n\n- 很多时候我们在打印`Lo"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio使用教程(第三弹).md",
"chars": 2928,
"preview": "AndroidStudio使用教程(第三弹)\n===\n\n熟悉了基本的使用之后,可能关心的就是版本控制了。\n\n- `SVN` \n - 下载`Subversion command line` "
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio使用教程(第二弹).md",
"chars": 2181,
"preview": "AndroidStudio使用教程(第二弹)\n===\n\n- 迁移`Eclipse`工程到`Android Studio` \n\n 官方文档中说`Android Studio`可以兼容`Eclipse`的现有工程,但"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio使用教程(第五弹).md",
"chars": 5597,
"preview": "AndroidStudio使用教程(第五弹)\n===\n\nCreate and Build an Android Studio Project\n---\n\n接下来是以下这四个部分: \n- Create projects and modu"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio使用教程(第六弹).md",
"chars": 2399,
"preview": "AndroidStudio使用教程(第六弹)\n===\n\nDebug\n---\n\n`Andorid Studio`中进行`debug`: \n- 在`Android Studio`中打开应用程序。 \n- 点击状态栏中的`Debug"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio使用教程(第四弹).md",
"chars": 4640,
"preview": "AndroidStudio使用教程(第四弹)\n===\n \nGradle\n---\n\n讲解到这里我感觉有必要说明一下`Gradle`。 \n`Gradle`是一个基于`Apache Ant`和`Apache Maven`概念的项目"
},
{
"path": "docs/android/AndroidNote/AndroidStudioCourse/AndroidStudio提高Build速度.md",
"chars": 3365,
"preview": "AndroidStudio提高Build速度\n===\n\n`Android Studio`自动发布以来,凭借其强大的功能,很快让开发者都投入到它的阵营下。但是也问题,就是`Build`速度太慢了。\n\n之前也根据网上的资料,修改了一些配置,但是"
},
{
"path": "docs/android/AndroidNote/Android基础/Activity详细解析.md",
"chars": 8052,
"preview": "# Activity是什么?\n\n我们都知道android中有四大组件(Activity 活动,Service 服务,Content Provider 内容提供者,BroadcastReceiver 广播接收器),Activity是我们用的最"
},
{
"path": "docs/android/AndroidNote/Android基础/Android-SQLite的基本使用.md",
"chars": 6737,
"preview": "# 概述\n\n Android 也提供了几种方法用来保存数据,使得这些数据即使在程序结束以后依然不会丢失。这些方法有: \n\n - **文本文件**:可以保存在应用程序自己的目录下,安装的每个app都会在/data/data/目录下创"
},
{
"path": "docs/android/AndroidNote/Android基础/Android中相机与相册的详细使用.md",
"chars": 8483,
"preview": "目前主流app都具有上传头像啊,上传图片的功能,看起来好简单的需求,但是其实这里面有一点点不同的地方。先说一下我的思路,因为开发周期的问题,并没有打算自定义相机与图片查询工具,打算采用系统相机和图片查看工具,最开始我打算调用系统的剪裁并且取"
},
{
"path": "docs/android/AndroidNote/Android基础/Android异步任务机制之AsycTask.md",
"chars": 3499,
"preview": "\n> 在Android中实现异步任务机制有两种方式,**Handler**和**AsyncTask**。 \n> \n> Handler已经在上一篇文章 [异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析"
},
{
"path": "docs/android/AndroidNote/Android基础/Android数据存储的五种方式.md",
"chars": 12442,
"preview": "\n## 1、概述\n \n\n Android提供了5种方式来让用户保存持久化应用程序数据。根据自己的需求来做选择,比如数据是否是应用程序私有的,是否能被其他程序访问,需要多少数据存储空间等,分别是: \n \n</br>\n\n① 使用Sha"
},
{
"path": "docs/android/AndroidNote/Android基础/Android获取SHA1.md",
"chars": 302,
"preview": "# Android获取SHA1\n\n\n\n1. 在Android Studio中打开Terminal或者进入控制台\n2. cd到jdk的bin目录下\n3. 输入命令 ``keytool -list -keystore /Users/mac/Wo"
},
{
"path": "docs/android/AndroidNote/Android基础/Android跟随手指移动的view.md",
"chars": 3057,
"preview": "> 实现一个跟随手指移动的view其实是特别容易实现的,不过有的时候还是挺有用的,最近做的视频互动软件就有这样的需求,大概几十行代码就可以搞定,然后记录一下吧。\n\n实现的主要思想,就是利用onTouchListener,然后判断出手指按下的"
},
{
"path": "docs/android/AndroidNote/Android基础/BroadcastReceiver详细解析.md",
"chars": 6473,
"preview": "# BroadcastReceiver的定义\n\n 广播是一种广泛运用的在应用程序之间传输信息的机制,主要用来监听系统或者应用发出的广播信息,然后根据广播信息作为相应的逻辑处理,也可以用来传输少量、频率低的数据。\n\n 在实现开机启动服务和"
},
{
"path": "docs/android/AndroidNote/Android基础/ContentProvider实例详解.md",
"chars": 12988,
"preview": "# 1.ContentProvider是什么?\n\n ContentProvider(内容提供者)是Android的四大组件之一,管理android以结构化方式存放的数据,以相对安全的方式封装数据(表)并且提供简易的处理机制和统一的访问接口"
},
{
"path": "docs/android/AndroidNote/Android基础/Handler,Looper,MessageQueue关系.md",
"chars": 11951,
"preview": "\n# 1、Handler的由来\n\n \n 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程。\n\n Android的UI操作并不是线程安全的(出于性能优化"
},
{
"path": "docs/android/AndroidNote/Android基础/IntentService详细解析.md",
"chars": 3509,
"preview": "# IntentService定义\n\n IntentService继承与Service,用来处理异步请求。客户端可以通过startService(Intent)方法传递请求给IntentService。IntentService在onCr"
},
{
"path": "docs/android/AndroidNote/Android基础/RecyclerView的简介.md",
"chars": 16200,
"preview": "RecyclerView\n\n一、简介\n\n这个是谷歌官方出的控件,使我们可以非常简单的做出列表装的一个控件,当然recyclerview的功能不止这些,它还可以做出瀑布流的效果,这是一个非常强大的控件,内部自带viewholder可以使我们非"
},
{
"path": "docs/android/AndroidNote/Android基础/Service详细解析.md",
"chars": 9427,
"preview": "# 什么是服务? \n\n Service是一个应用程序组件,它能够在后台执行一些耗时较长的操作,并且不提供用户界面。服务能被其它应用程序的组件启动,即使用户切换到另外的应用时还能保持后台运行。此外,应用程序组件还能与服务绑定,并与服务进行"
},
{
"path": "docs/android/AndroidNote/Android基础/tablayout记录.md",
"chars": 841,
"preview": "# TabLayout记录\n\n今天用TabLayout的时候发现,TabLayout的setOnPageChangeListener的方法过期了,良好的编程习惯是不在项目中使用过时的方法的,所以要找一个替代的方案:\n\n``addOnPage"
},
{
"path": "docs/android/AndroidNote/Android基础/test.kt",
"chars": 1,
"preview": "\n"
},
{
"path": "docs/android/AndroidNote/Android基础/图片缓存原理.md",
"chars": 8089,
"preview": "> 移动开发本质上就是手机和服务器之间进行通信,需要从服务端获取数据。反复通过网络获取数据是比较耗时的,特别是访问比较多的时候,会极大影响了性能,Android中可通过缓存机制来减少频繁的网络操作,减少流量、提升性能。\n\n# 实现原理\n\n"
},
{
"path": "docs/android/AndroidNote/Android开源框架相关/Android当下最流行的开源框架总结.md",
"chars": 26071,
"preview": "# Android中能够简化开发流程的一些框架\n\n> 本文介绍的是一些博主在开发过程中经常用到的Android开源框架,所谓开源框架我的理解就是别人封装好的代码,可以直接拿过来使用,并且源码也全部公开的代码库。\n> 我对于开源框架的使用的态"
},
{
"path": "docs/android/AndroidNote/Android开源框架相关/Android黑科技——ButterKnifeZelezny.md",
"chars": 891,
"preview": "> 先上一张效果图:\n\n\n"
},
{
"path": "docs/android/AndroidNote/Android开源框架相关/Picasso-android-load-image-layout.md",
"chars": 1332,
"preview": "> 以前一直都是用Picasso将图片设置在imageView上面,今天有个项目需求,是将imageView设置在layout的background上面,特意查了一下,现在打算记录一下。\n\n```\npicasso一般的用法\n\nPicasso"
},
{
"path": "docs/android/AndroidNote/Android开源框架相关/RxJava+retrofit2实现安卓中网络操作.md",
"chars": 10918,
"preview": "\n.md",
"chars": 11848,
"preview": "# AndroidStudio使用教程(第一弹)\n\n本文为转载文章:原文地址:https://github.com/CharonChui/AndroidNote\n\n`Android Studio`是一套面世不久的`IDE`(即集成开发环境)"
},
{
"path": "docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第七弹).md",
"chars": 13282,
"preview": "# AndroidStudio使用教程(第七弹)\n\n本文为转载文章:原文地址:https://github.com/CharonChui/AndroidNote\n\n\n本文讲解一下`Gradle`的应用,大家都知道`Gradle`使用起来非常"
},
{
"path": "docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第三弹).md",
"chars": 2983,
"preview": "# AndroidStudio使用教程(第三弹)\n\n本文为转载文章:原文地址:https://github.com/CharonChui/AndroidNote\n\n\n熟悉了基本的使用之后,可能关心的就是版本控制了。\n\n- `SVN` "
},
{
"path": "docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第二弹).md",
"chars": 2237,
"preview": "# AndroidStudio使用教程(第二弹)\n\n\n本文为转载文章:原文地址:https://github.com/CharonChui/AndroidNote\n\n\n- 迁移`Eclipse`工程到`Android Studio` "
},
{
"path": "docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第五弹).md",
"chars": 5653,
"preview": "# AndroidStudio使用教程(第五弹)\n\n本文为转载文章:原文地址:https://github.com/CharonChui/AndroidNote\n\n\n\nCreate and Build an Android Studio P"
},
{
"path": "docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第六弹).md",
"chars": 2455,
"preview": "# AndroidStudio使用教程(第六弹)\n\n本文为转载文章:原文地址:https://github.com/CharonChui/AndroidNote\n\n\n\nDebug\n---\n\n`Andorid Studio`中进行`debug"
},
{
"path": "docs/android/AndroidNote/Android编译器相关/AndroidStudio使用教程(第四弹).md",
"chars": 4696,
"preview": "# AndroidStudio使用教程(第四弹)\n\n本文为转载文章:原文地址:https://github.com/CharonChui/AndroidNote\n\n \nGradle\n---\n\n讲解到这里我感觉有必要说明一下`Gradle"
},
{
"path": "docs/android/AndroidNote/Android自定义View/Android事件分发机制.md",
"chars": 12012,
"preview": "> 在android开发中会经常遇到滑动冲突(比如ScrollView或是SliddingMenu与ListView的嵌套)的问题,需要我们深入的了解android事件响应机制才能解决,事件响应机制已经是android开发者必不可少的知识。"
},
{
"path": "docs/android/AndroidNote/Android自定义View/PathMeasure.md",
"chars": 2953,
"preview": "# PathMeasure\n\nPathMeasure是一个测量Path的路径的一个方法,我们今天的demo就是要做这样一个小东西,它会反复测量,运动的路径,并且沿着路径运行。\n\n效果图:\n\n这篇文章,本文主要对自定义ViewGroup的过程的梳"
},
{
"path": "docs/android/AndroidNote/Android自定义View/自定义View——CameraView.md",
"chars": 3796,
"preview": "# 自定义view——CameraView\n\n> 作者:https://github.com/linsir6\n>\n> 文章:http://www.jianshu.com/p/bd91a2b1245d\n\n\n\n\n private boolean isNotificationEnable"
},
{
"path": "docs/android/AndroidNote/Android进阶/深入了解MVXX模式.md",
"chars": 4425,
"preview": "# 深入了解MV**模式\n\n\n\n> 前言:做客户端开发、前端开发,大致都应该听说过这么几个名词MVC、MVP、MVVM,这些架构的思想大多是为了解决界面应用程序复杂的逻辑问题。同时这些框架的核心目的在于,职责分离,不同的层次要做不同的事情。"
},
{
"path": "docs/android/AndroidNote/Android进阶/自定义RadioGroup.md",
"chars": 14722,
"preview": "# 自定义RadioGroup\n\n> 在Android系统中,自带的RadioGroup只能指定横向和纵向两种布局,所以有的时候我们需要自定义RadioGroup。\n\n\n首先分析一下,就是在系统自带的RadioGroup中,如果我们嵌套了,"
}
]
// ... and 540 more files (download for full content)
About this extraction
This page contains the full source code of the pengMaster/BestNote GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 740 files (4.7 MB), approximately 1.3M tokens, and a symbol index with 14 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.