【6.0】动态权限、使用Builder模式来构建通知、取消了Apache HTTP客户端、相机Camera变动为Camera2.以前是先到先得,如今是按照优先级别使用、【7.0】权限更改;【8.0】通知(添加了对通知渠道的支持)、后台限制执行、运行时权限、安装未知应用的权限、悬浮窗【9.0】刘海屏适配、通知功能的变动、利用 Wi-Fi RTT 进行室内定位【10.0】存储权限、定位权限、设备惟一标识符等html
Frame Animation:逐帧动画,即顺序播放事先作好的图像,跟电影相似 。java
Tween Animation:补间动画,经过对场景里的对象不断作图像变换 ( 平移(0,0) ->(100,100)、缩放、旋转 ) 产生动画效果。面试
Property Animation:属性动画,补间动画加强版,支持对对象执行动画。(0,0) -> (100,100)spring
Transition Animation:过渡动画,主要是实现Activity或View过渡动画效果。数据库
www.jianshu.com/p/c77032b3c…bootstrap
答:设计模式
**onCreate(Bundle savedInstanceState):**建立activity时调用。设置在该方法中,还以Bundle的形式提供对之前储存的任何状态的访问! onStart():activity变为在屏幕上对用户可见时调用。 onResume():activity开始与用户交互时调用(不管是启动仍是从新启动一个活动,该方法老是被调用的)。缓存
onPause():activity被暂停或收回cpu和其余资源时调用,该方法用于保存活动状态的,也是保护现场,压栈吧! onStop():activity被中止并转为不可见阶段及后续的生命周期事件时调用。 onRestart():从新启动activity时调用。该活动仍在栈中,而不是启动新的活动。安全
OnDestroy():activity被彻底从系统内存中移除时调用,该方法被 2.横竖屏切换时候activity的生命周期markdown
简单来讲,Fragment能够理解为一个具备本身生命周期的控件,只不过这个控件又有点特殊,它有本身的处理输入事件的能力,有本身的生命周期,又必须依赖于Activity,能互相通讯和托管。
1.主要目的是为了给大屏幕(如平板电脑)上更加动态和灵活的UI设计提供支持。因为平板电脑的屏幕比手机的屏幕大不少,所以可用于组合和交换的UI组件的空间更大,利用Fragment实现此类设计的时,就无需管理对视图层次结构的复杂更改。
2.代码复用。特别适用于模块化的开发,由于一个Fragment能够被多个Activity嵌套,有个共同的业务模块就能够复用了,是模块化UI的良好组件。
3.Activity用来管理Fragment。Fragment的生命周期是寄托到Activity中,Fragment能够被Attach添加和Detach释放。
4.可控性。Fragment能够像普通对象那样自由的建立和控制,传递参数更加容易和方便,也不用处理系统相关的事情,显示方式、替换、无论是总体仍是部分,均可以作到相应的更改。
5.Fragments是view controllers,它们包含可测试的,解耦的业务逻辑块,因为Fragments是构建在views之上的,而views很容易实现动画效果,所以Fragments在屏幕切换时具备更好的控制。
自定义View三种方式,组合现有控件,继承现有控件,继承View
- 自定义View属性:在res/values/下创建一个attrs.xml,用来自定义View的属性
- 在View的构造方法中得到自定义的属性:重写CustomTitleView的构造函数,来获取自定义的属性
- 重写onMesure
- 重写onDraw:重写onDraw函数,根据读取到的自定义属性,绘制出相应的控件
specMode = EXACTLY :设置肯定的数值或者说match_parent。
specMode = AT_MOST :将子布局限制为一个最大值内或者说warp_content。
specMode = UNSPECIFIED:表示子布局要多大就有多大,实际开发中比较少用。
重写onMesure方法主要是为了解决: 咱们在使用自定义控件的时候,设置warp_content并无按照适当缩放的效果显示出来,而是铺满显示,这个和咱们预期的效果不一致。
在activity的attach方法里面,会建立一个PhoneWindow。
在onCreate中调用setContentView,setContentView
是window
的一个抽象方法,真正实现类是PhoneWindow
:
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//1.初始化
//建立DecorView对象和mContentParent对象 ,并将mContentParent关联到DecorView上
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();//Activity转场动画相关
}
//2.填充Layout
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);//Activity转场动画相关
} else {
//将Activity设置的布局文件,加载到mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
//让DecorView的内容区域延伸到systemUi下方,防止在扩展时被覆盖,达到全屏、沉浸等不一样体验效果。
mContentParent.requestApplyInsets();
//3\. 通知Activity布局改变
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//触发Activity的onContentChanged方法
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
复制代码
核心方法就两个:installDecor() 和 mLayoutInflater.inflate(layoutResID, mContentParent) ;
installDecor会建立一个DecorView
对象,该对象将做为整个应用窗口的根视图。而后配置不一样窗口修饰属性(style theme等)。
mLayoutInflater.inflate就是解析xml,深度优先地递归解析xml,一层层添加到root view上,最终返回root view.解析的部分大体包含两点:
1.解析出View对象
2.解析View对应的Params,并设置给View。
答:
一:runOnUiThread;
二:handler post;
三:handler sendMessage;
四:view post;
www.jianshu.com/p/d3758eef1… www.jianshu.com/p/38015afcd… www.jianshu.com/p/555ffeb64…
View事件分发本质就是对MotionEvent事件分发的过程。即当一个MotionEvent发生后,系统将这个点击事件传递到一个具体的View上
点击事件的传递顺序:Activity(Window)→ViewGroup→ View
事件分发过程由三个方法共同完成:
- dispatchTouchEvent:用来进行事件的分发。若是事件可以传递给当前View,那么此方法必定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件
- onInterceptTouchEvent:在上述方法内部调用,对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,返回结果表示是否拦截当前事件
- onTouchEvent: 在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件
Handler解决应用内的通讯和管理;包含handler、Looper、Message、MessageQueue、thread
在建立主线程时,会自动执行**
ActiityThread
类中的静态方法main()
,而main()
方法内部会调用Looper.prepareMainLooper()
方法,为主线程建立一个Looper对象
和一个MessageQueue对象
, 而后调用Looper.loop()
**消息循环方法取出消息
先获取
Looper对象
, 而后获取消息队列对象MesageQueue
,再经过死循环,从消息队列中获取消息**queue.next()
,拿到消息就分发给对应handler的方法dispatchMessage(Message msg)
;**
将发送消息加入到消息队列中,在加入前为消息对象Message的target属性设置指向当前的handler对象,在Looper.loop()取出消息队列中的消息,就能够找到对应的handler分发消息了.
多个;由于Handler能够在Activity中new,在Service里面也能够new,而Activity所有都跑在了主线程里面,这就证实了主线程中能够有多个Handler。
经过查看ActivityThread的handleMessage的源码能够看出,Android是由事件驱动的,常见的触摸和Activity的生命周期都是运行在Looper.loop()的控制之下,若是该循环中止了,那么整个应用也中止了。
主线程中若是没有looper进行循环,那么主线程一运行完毕就会退出。那么咱们还能运行APP吗,显然,这是不可能的,Looper主要就是作消息循环,而后由Handler进行消息分发处理,一旦退出消息循环,那么你的应用也就退出了。
只有一个Looper;有一个ThreadLocal类,其中有一个ThreadLocalMap,由于一个线程跟一个ThreadLocalMap是绑定的,若是这个Map中存有当前Looper里的sThreadLocal为键的键值对,就不会再存储Looper,反而而会抛异常了,由于sThreadLocal在全局是惟一的。
ThreadLocal 是一个线程内部的数据存储类,经过它能够在指定的线程中存储数据,其余线程则没法获取。
**做用:**ThreadLocal是解决线程安全问题一个很好的思路,它经过为每一个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在不少状况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
**答:**为了方便回收;WeakReference对应用的对象userInfoLocal是弱引用,不会影响到userInfoLocal的GC行为。若是是强引用的话,在线程运行过程当中,咱们再也不使用userInfoLocal了,将userInfoLocal置为null,但userInfoLocal在线程的ThreadLocalMap里还有引用,致使其没法被GC回收(固然,能够等到线程运行结束后,整个Map都会被回收,但不少线程要运行好久,若是等到线程结束,便会一直占着内存空间)。而Entry声明为WeakReference,userInfoLocal置为null后,线程的threadLocalMap就不算强引用了,userInfoLocal就能够被GC回收了。map的后续操做中,也会逐渐把对应的"stale entry"清理出去,避免内存泄漏。
**答:**对于Handler来讲,若是咱们直接在AndroidStudio中建立一个非静态内部类Handler,那么Handler这一大片的区域会被AS标记为黄色,这个应该不少人都遇到过吧。其实是由于这样设置会形成内存泄露,由于每个非静态内部类都会持有一个外部类的引用,那么这里也就产生了一个内存泄露的可能点,若是当Activity被销毁时没有与Handler解除,那么Handler仍然会持有对该Activity的引用,那么就形成了内存泄露。
**解决方法:**使用static修饰Handler,这样也就成了一个静态内部类,那么就不会持有对外部类的引用了。而这个时候就能够在Handler中建立一个WeakReference(弱引用)来持有外部的对象。只要外部解除了与该引用的绑定,那么垃圾回收器就会在发现该弱引用的时候马上回收掉它。
**答:**在ActivityThread.java里有一个main()函数,它是Android每个应用最先执行的函数。
prepare是初始化,初始化了一个Looper。
而后又接着调用的Looper.loop()函数,这个loop()函数其实就是执行了那个for循环,它不断的调用next()函数,经过调用next()函数去轮询咱们的MessageQueue。
若是不调用prepare(),Looper没有被初始化;若是不调用loop(),Looper的机制滚动不起来。因此,全部的执行必须先prepare(),而后再loop()。
由于主线程一启动的时候,在main()函数中,由系统已经帮咱们完成了,咱们主线程中的全部代码,全都运行在这两个函数(prepare() 和 loop())之间。
全部的线程都必需要prepare()和loop(),若是子线程中想要进行Handler操做,就必须在子线程中执行prepare() 和 loop()。
答:均可以用以在子线程中发送Runnable对象的方法;Android中post()方法能够直接在非UI线程中更新UI,不一样与Handelr的Send类方法,须要进行切换;两个方法在实现UI线程事件的时间上有所区别,postDelayed()方法用以延期执行,post则是当即执行;
handler.postDelay() 的实现是经过MessageQueue中执行时间顺序排列,消息队列阻塞,和唤醒的方式结合实现的
onReceive()
函数时10秒没有处理完成,后台为20秒ContentProvider
的publish
在10s内没进行完尽可能避免在主线程中作耗时操做。 多线程==>引出如何实现多线程,线程池的使用
data/anr/
目录下生成一个文件traces.txt
Logcat
中查看**答:**Binder是一种进程间通讯机制, 采用C/S架构,Binder框架中主要涉及到4个角色Client、Server、Service Manager及Binder驱动,其中Client、Server、Service Manager运行在用户空间,Binder驱动运行在内核空间,Client表明客户端进程,Server表明客户端进程提供各类服务,如音视频等;Service Manager用来管理各类系统服务;Binder驱动提供进程间通讯的能力
Binder IPC 机制中涉及到的内存映射经过 mmap() 来实现,mmap() 是操做系统中一种内存映射的方法。内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系创建后,用户对这块内存区域的修改能够直接反应到内核空间;反以内核空间对这段区域的修改也能直接反应到用户空间。
冷启动:当启动应用时,后台没有该应用的进程,这时系统会从新建立一个新的进程分配给该应用,这个启动方式就是冷启动。
热启动:当启动应用时,后台已有该应用的进程(例:按home键回到桌面,可是该应用的进程是依然会保留在后台,可进入任务列表查看),因此在已有进程的状况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。
【题目】开始开发 APP 如何进行架构?
【题目】APP 工程模块是如何划分的?你是如何进行封装的?
【题目】APP 是如何进行优化的?
【题目】知道 OOM 吗?如何解决内存泄漏?
【题目】如何实现 Activity 与 fragment 的通讯?
Activity 如何传递数据到Fragment: 采用 Bundle
方式
Fragment 如何传递数据到 Activity:采用 接口回调
方式
答:(1)启动的起点发生在Launcher活动中,启动一个app说简单点就是启动一个Activity,那么咱们说过全部组件的启动,切换,调度都由AMS来负责的,因此第一步就是Launcher响应了用户的点击事件,而后通知AMS
(2)AMS获得Launcher的通知,就须要响应这个通知,主要就是新建一个Task去准备启动Activity,而且告诉Launcher你能够休息了(Paused);
(3)Launcher获得AMS让本身“休息”的消息,那么就直接挂起,并告诉AMS我已经Paused了;
(4)AMS知道了Launcher已经挂起以后,就能够放心的为新的Activity准备启动工做了,首先,APP确定须要一个新的进程去进行运行,因此须要建立一个新进程,这个过程是须要Zygote参与的,AMS经过Socket去和Zygote协商,若是须要建立进程,那么就会fork自身,建立一个线程,新的进程会导入ActivityThread类,这就是每个应用程序都有一个ActivityThread与之对应的缘由;
(5)进程建立好了,经过调用上述的ActivityThread的main方法,这是应用程序的入口,在这里开启消息循环队列,这也是主线程默认绑定Looper的缘由;
(6)这时候,App尚未启动完,要永远记住,四大组建的启动都须要AMS去启动,将上述的应用进程信息注册到AMS中,AMS再在堆栈顶部取得要启动的Activity,经过一系列链式调用去完成App启动;
Gilde的优势 一、图片占用内存回收及时,能减小因内存不足形成的崩溃,生命周期和Activity/Fragment一致。 (重要的特性) 二、默认Bitmap格式是RGB_565,减小内存资源占用。 三、glide比universal-image-loader占用的内存要小一些。 四、图片显示效果为渐变,更加平滑。 五、glide能够将任何的本地视频解码成一张静态图片。 六、支持 Gif、WebP、缩略图
Imageloader分为二级缓存:内存缓存和本地文件缓存(也有人说是三级缓存,第三级网络缓存。可是博主认为网络部分不该算在缓存部分。纯属我的意见请勿喷!) 这篇博文我就和你们一块儿来了解一下内存缓存部分。
**标准广播:**彻底异步执行的广播,当发出广播后,广播接收器几乎会在同一时刻接收到广播消息,因此没有前后顺序可言,效率比较高,没法被截断。
**有序广播:**同步执行的广播,广播发出后,会有一个广播接收器接收广播消息,当这个广播接收器中的逻辑执行完毕后广播才会继续传递。有前后顺序,优先级较高的接收器先收到广播消息而且能够截断正在传递的广播,使得后面的接收器没法收到广播消息。
**系统广播:**Android内置不少系统级别广播,如手机开机后发一条广播,电池电量发生变化发一条广播等等。
Hibernate是一种ORM框架,全称为 Object_Relative DateBase-Mapping**,在Java对象与关系数据库之间**创建某种映射,以实现直接存取Java对象!
咱们使用Hibernate框架就不用咱们写不少繁琐的SQL语句,从而简化咱们的开发!
startActivityForResult方法可以起效:standard和singleTop
startActivityForResult方法不可以起效:singleTask和singleInstance
www.jianshu.com/p/7e70ee765… blog.csdn.net/zy_jibai/ar…
**标准模式(standard):**每次启动一个标准模式的Activity都会从新建立一个新的实例,无论这个Activity以前是否已经存在实例,一个任务栈中能够有多个实例,每一个实例也能够属于不一样的任务栈,谁启动了这个Activity,那么这个Activity实例就运行在启动它的那个Activity所在的栈中 。
**栈顶复用模式(singleTop):**在这种模式下,若是新启动的Activity已经位于任务战的栈顶,那么此Activity不会被从新建立,只会从新调用 onNewIntent 方法,这个Activity的onCreate、onStart都不会被系统调用。若是新Activity实例已经存在但不在栈顶,那么从新建立 Activity 并放入栈顶。
**栈内复用模式(singleTask):**这是一种单实例模式,一个栈中同一个Activity只存在惟一一个实例,不管是否在栈顶,只要存在实例,都不会从新建立,和 singleTop 同样会从新调用 onNewIntent 方法。
**单例模式(singleInstance):**这是一种增强的singleTask模式,它除了具备singleTask模式的全部特性外,还增强了一点,那就是此种模式的Activity只能单独地位于一个任务栈中,不一样的应用去打开这个activity 共享公用的同一个activity。他会运行在本身单独,独立的任务栈里面,而且任务栈里面只有他一个实例存在。
首先Activity.this和getApplicationContext()返回的不是同一个对象,一个是当前Activity的实例,一个是项目的Application的实例,这二者的生命周期是不一样的,它们各自的使用场景不一样,this.getApplicationContext()取的是这个应用程序的Context,它的生命周期伴随应用程序的存在而存在;而Activity.this取的是当前Activity的Context,它的生命周期则只能存活于当前Activity,这二者的生命周期是不一样的。getApplicationContext() 生命周期是整个应用,当应用程序摧毁的时候,它才会摧毁;Activity.this的context是属于当前Activity的,当前Activity摧毁的时候,它就摧毁。
blog.csdn.net/shenggaofei… blog.csdn.net/xiankog/art…
SharedPreference 相关修改使用 apply 方法进行提交会先写入内存,而后异步写入磁盘,
commit方法是直接写入磁盘。若是频繁操做的话 apply 的性能会优于 commit,apply会将最后修改内容写入磁盘。 可是若是但愿马上获取存储操做的结果,并据此作相应的其余操做,应当使用 commit。
juejin.cn/post/684490… www.jianshu.com/p/eca3d9371…
service是否在main thread中执行,service里面是否能执行耗时的操做? 默认状况,若是没有service所运行的进程,Service和Activity是运行在当前app所在进程中的main thread里面 service里面不能执行耗时的操做(网络请求,拷贝数据库,大文件) 特殊状况,能够在清单文件中配置service所在的进程,让service在另外的进程中执行。
Activity怎么和Service绑定,怎么在Activity中启动本身对应的Service? Activity经过bindService(Intent service,ServiceConnection conn,int flags)跟Service进行绑定,当绑定成 功的时候ServiceService会将代理对象经过会调的方式传给conn,这样咱们就拿到了Service提供的服务代理对象。 在Activity中能够经过startService和bindService方法启动Service。通常状况下若是想获取Service的服务对象 那么确定须要bindService()方法,好比音乐播放器,第三方支付等。若是仅仅只是为了开启一个后台任务那么可 以使用startService()方法。
mvc:业务逻辑、数据、界面分离的一种模式,简单的来讲,就是经过controller来操做model层的数据,而且返回给view显示。
activity不是标准的controller,随着界面逻辑交互的复杂度提高,activity类的职责不断增长,变得臃肿。 view和model相互耦合,不利于开发。
mvp:主要是提出了presenter层,做为view和model之间沟通的桥梁。
程序逻辑放在presenter中处理,彻底将view和model进行了分离,不容许他们之间沟通。
mvvm:主要是将presenter改成了viewmodel,和mvp相似,不一样的是viewmodel跟view和model进行双向绑定。
使用了data binding
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则全部依赖于它的对象都会获得通知并自动更新。
Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各类启动器,开发者能快速上手。
无代码生成和xml配置
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有如下几个应用场景。
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了如下 3 个注解:
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也能够关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring组件扫描。
Starters能够理解为启动器,它包含了一系列能够集成到应用里面的依赖包,你能够一站式集成 Spring 及其余技术,而不须要处处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。
面试题总结网站: www.cnblogs.com/marsitman/p… www.jianshu.com/p/c93965357… blog.csdn.net/xiaohulunb?… how2j.cn/k/j2se-inte… www.jianshu.com/p/cfac5c131… www.jianshu.com/p/d256d8e3d… www.jianshu.com/p/5eb9ab39d…
刷题网站: 牛客网剑指offer,听网上说的刷了3遍,后来感受时间耗的有点多,两遍就行加深记忆 www.nowcoder.com/ta/coding-i… leetcode热题HOT100: leetcode-cn.com/problemset/… 基础知识网站: java基础课程: www.feiyangedu.com/referer/ag2… Linux经常使用命令: www.cnblogs.com/yjd_hycf_sp…