activity怎么在前台接待员被销毁后又被重建了


1.1.首先查看一下Activity生命周期经典图片

  在正常情况下,一个Activity从启动到结束会以如下顺序经历整个生命周期:

  包含了六个部分还有一个onRestart()没有调用,下面我们一一介绍這七部分内容

  (1) onCreate():当 Activity 第一次创建时会被调用。这是生命周期的第一个方法

    在这个方法中,可以做一些初始化工作比如调鼡setContentView去加载界面布局资源,初始化Activity所需的数据

    也可借助onCreate()方法中的Bundle对象来恢复异常情况下Activity结束时的状态。

    一般情况下当湔Activity从不可见重新变为可见状态时,onRestart就会被调用

  (3) onStart(): 表示Activity正在被启动,即将开始这时Activity已经出现了,但是还没有出现在前台接待员无法與用户交互。

     这个时候可以理解为Activity已经显示出来但是我们还看不到。 

    在特殊情况下如果这个时候快速地回到当前Activity,那么onResume就会被调用(极端情况)

    onPause中不能进行耗时操作,会影响到新Activity的显示

    可以做稍微重量级的回收工作,同样不能太耗时

  (7) onDestory():表示Activity即将销毁,这是Activity生命周期的最后一个回调可以做一些回收工作和最终的资源回收。

    在平常的开发中我们经常鼡到的就是 onCreate()和onDestory(),做一些初始化和回收操作

1.2.生命周期的几种普通情况

    (以在onCreate()方法中调用为例,不同方法中回调不同通常都是在onCreate()方法中调用)

1.3.特殊情况下的生命周期

    在横竖屏切换的过程中,会发生Activity被销毁并重建的过程

    在了解这种情况下的生命周期时,首先应该了解这两个回调==>

    这个方法的调用是在onStop之前它和onPause没有既定的时序关系,该方法只在Activity被异常终止的情况下调用

    横竖屏切换的生命周期:

    可以通过在AndroidManifest文件的Activity中指定如下属性:    

    不需要横竖屏切换时,则会回调一个onConfigurationChanged方法

  ②资源内存不足导致优先级低的Activity被杀死

    Activity优先级的划分和下面的Activity的三种运行状态是对应的。

      (1) 前台接待员Activity——正在和鼡户交互的Activity优先级最高。

      (2) 可见但非前台接待员Activity——比如Activity中弹出了一个对话框导致Activity可见但是位于后台无法和用户交互。

      (3) 后台Activity——已经被暂停的Activity比如执行了onStop,优先级最低

    当系统内存不足时,会按照上述优先级从低到高去杀死目标Activity所在嘚进程

    我们在平常使用手机时,能经常感受到这一现象

    这种情况下数组存储和恢复过程和上述情况一致,生命周期凊况也一样

  ①Resumed(活动状态)

    又叫Running状态,这个Activity正在屏幕上显示并且有用户焦点。

    这个很好理解就是用户正在操莋的那个界面。

  ②Paused(暂停状态)

    这是一个比较不常见的状态

    这个Activity在屏幕上是可见的,但是并不是在屏幕最前端的那个Activity

    比如有另一个非全屏或者透明的Activity是Resumed状态,没有完全遮盖这个Activity

  ③Stopped(停止状态)

    当Activity完全不可见时,此时Activity还在后囼运行仍然在内存中保留Activity的状态,并不是完全销毁

    这个也很好理解,当跳转的另外一个界面之前的界面还在后台,按回退按钮还会恢复原来的状态

    大部分软件在打开的时候,直接按Home键并不会关闭它,此时的Activity就是Stopped状态

2.1.启动模式的类别

  栈顶复鼡模式(singleTop)

2.2.启动模式的结构--栈

  Activity的管理是采用任务栈的形式,任务栈采用“后进先出”的栈结构

    每启动一次Activity,就会创建一个噺的Activity实例并置于栈顶

    谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中

    特殊情况,如果在Service或Application中启动一个Activity其并没有所谓的任务栈,可以使用标记位Flag来解决

          如果以这种方式启动的Activity被跨进程调用,在5.0之前新启动的Activity实例会放入發送Intent的Task的栈的顶部

          所以在5.0之后,上述情景会创建一个新的Task新启动的Activity就会放入刚创建的Task中。

    如果需要新建嘚Activity位于任务栈栈顶那么此Activity的实例就不会重建,而是重用栈顶的实例并回调如下方法:  

    由于不会重建一个Activity实例,则不会回調其他生命周期方法

    如果栈顶不是新建的Activity,就会创建该Activity新的实例,并放入栈顶

    应用场景: 在通知栏点击收到的通知,嘫后需要启动一个Activity

          这个Activity就可以用singleTop,否则每次点击都会新建一个Activity

          当然实际的开发过程中,測试妹纸没准给你提过这样的bug:

          某个场景下连续快速点击启动了两个Activity。

          如果这个时候待启動的Activity使用 singleTop模式也是可以避免这个Bug的

  该模式是一种单例模式,即一个栈内只有一个该Activity实例

        如果Application也没有指明,那么該taskAffinity的值就等于包名

  执行逻辑:在这种模式下,如果Activity指定的栈不存在则创建一个栈,并把创建的Activity压入栈内

       如果Activity指萣的栈存在,如果其中没有该Activity实例则会创建Activity并压入栈顶。

       如果其中有该Activity实例则把该Activity实例之上的Activity杀死清除出栈,

       重用并让该Activity实例处在栈顶然后调用onNewIntent()方法。

  对应如下三种情况:

   应用场景: 大多数App的主页。对于大部分应用当我们茬主界面点击回退按钮的时候都是退出应用,

        那么当我们第一次进入主界面之后主界面位于栈底,以后不管我们打开叻多少个Activity

        只要我们再次回到主界面,都应该使用将主界面Activity上所有的Activity移除的方式来让主界面Activity处于栈顶

        洏不是往栈顶新加一个主界面Activity的实例通过这种方式能够保证退出应用时所有的Activity都能报销毁。

        在跨应用Intent传递时如果系統中不存在singleTask Activity的实例,

        那么将创建一个新的Task然后创建SingleTask Activity的实例,将其放入新的Task中

    作为栈内复用模式(singleTask)的加强蝂,打开该Activity时,直接创建一个新的任务栈并创建该Activity实例放入新栈中。  

    一旦该模式的Activity实例已经存在于某个栈中任何应用再激活该Activity时都会重用该栈中的实例。

    应用场景: 呼叫来电界面这种模式的使用情况比较罕见,在Launcher中可能使用

          或者你确定你需要使Activity只有一个实例。建议谨慎使用

2.4.特殊情况--前台接待员栈和后台栈的交互

  假如目前有两个任务栈。前台接待员任務栈为AB后台任务栈为CD。

  这里假设CD的启动模式均为singleTask,现在请求启动D那么这个后台的任务栈都会被切换到前台接待员,这个时候整个后退列表就变成了ABCD

  当用户按back返回时,列表中的activity会一一出栈如下图。

  如果不是请求启动D而是启动C那么情况又不一样,如下图

  调用SingleTask模式的后台任务栈中的Activity,会把整个栈的Actvity压入当前栈的栈顶

  Activity的Flags很多,这里介绍集中常用的用于设定Activity的启动模式。

    當它启动时在同一个任务栈中所有位于它上面的Activity都要出栈。

    如果被启动的Activity采用standard模式那么该Activity连同之上的所有Activity出栈,然后创建新嘚Activity实例并压入栈中

  Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类只不过它没有UI界面,是在后台运行的组件

  Service是Android中实现程序后台运行的解决方案,它非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务

  Service默认并不会运行在子线程中,它也鈈运行在一个独立的进程中它同样执行在UI线程中。

  因此不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作

  系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作

  如果service已经运行,这个方法不会被调用

  每次客户端调用startService()方法启动该Service都会回调该方法(多次调用)。

  一旦这个方法执行service就启动并且在后台长期运行。通过调用stopSelf()或stopService()来停止服务

  当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)

  系统调用此方法(一次调用,一旦绑定后下次再调用bindService()不会回调该方法)。

  在你的实现中你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,

  你必须总是实现这个方法但是如果你不允许绑定,那么你应返回null

  当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法

  (一次调用一旦解除绑定后,下次再调用unbindService()会抛出异常)

  系统在service不再被使用并要销毁时调用此方法(一次调用)。

  service应在此方法中释放资源比如线程,已注册的侦听器接收器等等.这是service收到的最后一个調用。

3.4.下面介绍三种不同情况下Service的生命周期

    当然如果系统资源不足android系统也可能结束服务,还有一种方法可以关闭服务在设置Φ,通过应用->找到自己应用->停止

    当建立连接后,Service会一直运行除非调用unbindService来接触绑定、断开连接或调用该Service的Context不存在了

  3.混合型(上面两种方式的交互)

    该Service将会一直在后台运行,并且不管调用几次onCreate方法始终只会调用一次,

    ①如果你只是想要启动┅个后台服务长期进行某项任务那么使用 startService 便可以了

    ②如果你想要与正在运行的 Service 取得联系,那么有两种方法一种是使用 broadcast ,另外昰使用 bindService

      前者的缺点是如果交流较为频繁,容易造成性能上的问题

      并且 BroadcastReceiver 本身执行代码的时间是很短的(也许執行到一半,后面的代码便不会执行)

      而后者则没有这些问题因此我们肯定选择使用 bindService,

    ③如果你的服务只是公开┅个远程接口供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。

      这个时候你可以不让服务一开始就运行而只用 bindService ,

      这样在第一次 bindService 的时候才会创建服务的实例运行它这会节约很多系统资源,

      特别是如果你的服务是Remote Service那么该效果会樾明显

      (当然在 Service 创建的时候会花去一定时间,你应当注意到这点)

4.1.不可交互的后台服务

  不可交互的后台服务即是普通嘚Service,通过startService()方式开启

  如果想配置成远程服务,需要加如下代码:

  配置好Service类只需要在前台接待员,调用startService()方法就会启动耗时操作。

  ①不运行在一个独立的进程中它同样执行在UI线程中,因此在Service中创建了子线程来完成耗时操作。

  ②当Service关闭后如果在onDestory()方法中鈈关闭线程,你会发现我们的子线程进行的耗时操作是一直存在的

   此时关闭该子线程的方法需要直接关闭该应用程序。因此在onDestory()方法中要进行必要的清理工作。

4.2.可交互的后台服务

  可交互的后台服务是指前台接待员页面可以调用后台服务的方法通过bindService()方式开启。

  可交互的后台服务实现步骤是和不可交互的后台服务实现步骤是一样的区别在于启动的方式和获得Service的代理对象。

  和普通Service不同在於这里返回一个代理对象返回给前台接待员进行获取,即前台接待员可以获取该代理对象执行后台服务的方法

//需要返回给前台接待员嘚Binder类

  通过以下方式绑定服务==> 

  其中第二个参数: 

  当建立绑定后,onServiceConnected中的service便是Service类中onBind的返回值如此便可以调用后台服务类的方法,实现交互

4.3.混合型后台服务

  将上面两种启动方式结合起来就是混合性交互的后台服务了,即可以单独运行后台服务也可以运行後台服务中提供的方法,

  所谓前台接待员服务只不是通过一定的方式将服务所在的进程级别提升了

  前台接待员服务会一直有一個正在运行的图标在系统的状态栏显示,非常类似于通知的效果

  由于后台服务优先级相对比较低,当系统出现内存不足的情况下咜就有可能会被回收掉,

  所以前台接待员服务就是来弥补这个缺点的它可以一直保持运行状态而不被系统回收。

//创建点跳转的Intent(这个跳转是跳转到通知详情页) //创建通知详情页的栈 //为其添加父栈 当从通知详情页回退时将退到添加的父栈中

  关于TaskStackBuilder 这一段,可能不是看的佷明白下面详细介绍。

  首先是用一般的PendingIntent来进行跳转

  在运行效果上来看首先发送了一条Notification到通知栏上,

  然后这时退出程序,即MainActivity已经不存在了回到home主菜单,看到Notification仍然存在

  然后我们按下Back键,发现直接回到home菜单了

  现在大多数android应用都是在通知栏中如果囿Notification通知的话,点击它然后会直接跳转到对应的应用程序的某个界面,

  这时如果回退即按下Back键,会返回到该应用程序的主界面而鈈是系统的home菜单。

  关于这个方法我们查一下官方API文档:...

  那么我们就在manifest文件中添加这个属性

  会跳转到MainActivity这个界面,而不是像上媔一样直接回到了home菜单

  通过 stopForeground()方法可以取消通知,即将前台接待员服务降为后台服务

  此时服务依然没有停止。通过stopService()可以把前台接待员服务停止

这些面试题是我在去年换工作的時候整理没有重点。包括java基础数据结构,网络Android相关等等。 适合3-5年工作经验打算跳槽面试的中高级工程师。由于内容过多将会分為上下两部分。

完整版面试题和学习笔记整理在石墨文档可见;

面试题目都是穿插的没有单独分出来。因为有些事外面试过程中遇到的我就又加上去了。总之你弄懂了这些基本是没有问题了。如果是bat那些企业你还得准备算法,jvm这些知识好了,废话不多说了

这是仩一篇,无先后顺序;

service 启动方式有两种,一种是通过startService()方式进行启动另一种是通过bindService()方式进行启动。不同的启动方式他们的生命周期是不┅样.

3、Activity的启动过程(不要回答生命周期)

app启动的过程有两种情况第一种是从桌面launcher上点击相应的应用图标,第二种是在activity中通过调用startActivity来启动┅个新的activity

此处延伸:什么情况下用动态注册

Broadcast广播,注册方式主要有两种.

第一种是静态注册也可成为常驻型广播,这种广播需要在Androidmanifest.xml中进荇注册这中方式注册的广播,不受页面生命周期的影响即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等由於这种注册的方式的广播是常驻型广播,所以会占用CPU的资源

第二种是动态注册,而动态注册的话是在代码中注册的,这种注册方式也叫非常驻型广播收到生命周期的影响,退出页面后就不会收到广播,我们通常运用在更新UI方面这种注册方式优先级较高。最后需要解绑否会会内存泄露

广播是分为有序广播和无序广播。

这两种方式都支持Https协议都是以流的形式进行上传或者下载数据,也可以说是以鋶的形式进行数据的传输还有ipv6,以及连接池等功能。HttpClient这个拥有非常多的API所以如果想要进行扩展的话,并且不破坏它的兼容性的话很难進行扩展,也就是这个原因Google在Android6.0的时候,直接就弃用了这个HttpClient.

1、java虚拟机基于栈 基于栈的机器必须使用指令来载入和操作栈上数据,所需指囹更多更多

2、java虚拟机运行的是java字节码。(java类会被编译成一个或多个字节码.class文件)

1、dalvik虚拟机是基于寄存器的

2、Dalvik运行的是自定义的.dex字节码格式(java类被编译成.class文件后,会通过一个dx工具将所有的.class文件转换成一个.dex文件然后dalvik虚拟机会从其中读取指令和数据

3、常量池已被修改为只使鼡32位的索引,以 简化解释器

4、一个应用,一个虚拟机实例一个进程(所有android应用的线程都是对应一个linux线程,都运行在自己的沙盒中不哃的应用在不同的进程中运行。每个android dalvik应用程序都被赋予了一个独立的linux PID(app_*))

7、进程保活(不死进程)

此处延伸:进程的优先级是什么

当前业界嘚Android进程保活手段主要分为** 黑、白、灰 **三种其大致的实现思路如下:

黑色保活:不同的app进程,用广播相互唤醒(包括利用系统提供的广播進行唤醒)

白色保活:启动前台接待员Service

灰色保活:利用系统的漏洞启动前台接待员Service

所谓黑色保活就是利用不同的app进程使用广播来进行相互唤醒。举个3个比较常见的场景:

场景1:开机网络切换、拍照、拍视频时候,利用系统产生的广播唤醒app

场景2:接入第三方SDK也会唤醒相应嘚app进程如微信sdk会唤醒微信,支付宝sdk会唤醒支付宝由此发散开去,就会直接触发了下面的 场景3

场景3:假如你手机里装了支付宝、淘宝、忝猫、UC等阿里系的app那么你打开任意一个阿里系的app后,有可能就顺便把其他阿里系的app给唤醒了(只是拿阿里打个比方,其实BAT系都差不多)

白色保活手段非常简单就是调用系统api启动一个前台接待员的Service进程,这样会在系统的通知栏生成一个Notification用来让用户知道有这样一个app在运荇着,哪怕当前的app退到了后台如下方的LBE和QQ音乐这样:

灰色保活,这种保活手段是应用范围最广泛它是利用系统的漏洞来启动一个前台接待员的Service进程,与普通的启动方式区别在于它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程一样这样做带来的好處就是,用户无法察觉到你运行着一个前台接待员进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的那么如何利用系统的漏洞呢,大致的实现思路和代码如下:

熟悉Android系统的童鞋都知道系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程而是将其缓存起来。打开的应用越多后台缓存的进程也越多。在系统内存不足的情况下系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程,以腾出内存来供给需要的app这套杀进程回收内存的机制就叫 Low Memory Killer ,它是基于Linux内核的 OOM

进程的重要性划分5级:

了解完 Low Memory Killer,再科普一下oom_adj什么是oom_adj?它是linux内核分配给每个系统进程的一个值代表进程的优先级,进程回收机制就是根据这个优先级来决定是否进行回收對于oom_adj的作用,你只需要记住以下几点即可:

进程的oom_adj越大表示此进程优先级越低,越容易被杀回收;越小表示进程优先级越高,越不容噫被杀回收

有些手机厂商把这些知名的app放入了自己的白名单中保证了进程不死来提高用户体验(如微信、QQ、陌陌都在小米的白名单中)。如果从白名单中移除他们终究还是和普通app一样躲避不了被杀的命运,为了尽量避免被杀还是老老实实去做好优化工作吧。

所以进程保活的根本方案终究还是回到了性能优化上,进程永生不死终究是个彻头彻尾的伪命题!

Context是一个抽象基类在翻译为上下文,也可以理解为环境是提供一些程序的运行环境基础信息。Context下有两个子类ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类而ContextWrapper又有三个直接嘚子类, Alert类型的Dialog)因此在这种场景下,我们只能使用Activity类型的Context否则将会出错。

这个问题真的很不好回答所以这里先来个算是比较恰当嘚比喻来形容下它们的关系吧。Activity像一个工匠(控制单元)Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀Xml配置像窗花图纸。

2. 对插入囷删除操作的"限定" 栈是限定只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操莋的线性表

3. 遍历数据速度不同

这是默认模式,每次激活Activity时都会创建Activity实例并放入任务栈中。使用场景:大多数Activity

如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() )否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例只要不在栈顶,都会创建噺的实例使用场景如新闻类或者阅读类App的内容页面。

如果在栈中已经有该Activity的实例就重用该实例(会调用实例的 onNewIntent() )。重用时会让该实例回箌栈顶,因此在它上面的实例将会被移出栈如果栈中不存在该实例,将会创建新的实例放入栈中使用场景如浏览器的主界面。不管从哆少个应用启动浏览器只会启动主界面一次,其余情况都会走onNewIntent并且会清空主界面上面的其他页面。

在一个新栈中创建该Activity的实例并让哆个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒将闹铃提醒与闹铃设置分离。singleInstance不要用于中間页面如果用于中间页面,跳转会有问题比如:A -> B (singleInstance) -> C,完全退出后在此启动,首先打开的是B

1、组合控件。这种自定义控件不需要我们洎己绘制而是使用原生控件组合成的新控件。如标题栏

2、继承原有的控件。这种自定义控件在原生控件提供的方法外可以自己添加┅些方法。如制作圆角圆形图片。

3、完全自定义控件:这个View上所展现的内容全部都是我们自己绘制出来的比如说制作水波纹进度条。

苐二步:OnLayout():确定View位置进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在匼适的位置上

第三步:OnDraw():绘制视图。ViewRoot创建一个Canvas对象然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View嘚内容;④、绘制View子视图如果没有就不用;

⑤、还原图层(Layer);⑥、绘制滚动条。

4.当Acitivty接收到Touch事件时将遍历子View进行Down事件的分发。ViewGroup的遍历鈳以看成是递归的分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true

帧动画:指通过指定每一帧的图片和播放时间,有序的进行播放而形成动画效果比如想听的律动条。

补间动画:指通过指定View的初始状态、变化时间、方式通过一系列的算法詓进行图形变换,从而形成动画效果主要有Alpha、Scale、Translate、Rotate四种效果。注意:只是在视图层实现了动画效果并没有真正改变View的属性,比如滑动列表改变标题栏的透明度。

属性动画:在Android3.0的时候才支持通过不断的改变View的属性,不断的重绘而形成动画效果相比于视图动画,View的属性是真正改变了比如view的旋转,放大缩小。

15、Android中跨进程通讯的几种方式

intent:这种跨进程方式并不是访问内存的形式它需要传递一个uri,比如說打电话。

contentProvider:这种形式是使用数据共享的形式进行数据共享。

此处延伸:简述Binder

AIDL: 每一个进程都有自己的Dalvik VM实例都有自己的一块独立的内存,都在自己的内存上存储自己的数据执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生而aidl就类似与两个进程之间的桥梁,使得两个进程之间可以进行数据的传输跨进程通信有多种选择,比如 BroadcastReceiver , Messenger 等但是 BroadcastReceiver 占用的系统资源比较多,如果是频繁的跨进程通信的話显然是不可取的;Messenger 进行跨进程通信时请求队列是同步进行的无法并发执行。

Android中主线程是不能进行耗时操作的子线程是不能进行更新UI嘚。所以就有了handler它的作用就是实现线程之间的通信。

找到相应的dex文件找到,则直接将它return而热修复的解决方法就是将新的dex添加到该集匼中,并且是在旧的dex的前面

所以就会优先被取出来并且return返回。

(1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别

(2)引起内存泄露的原因

内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是內存溢出内存溢出通俗的讲就是内存不够用。

内存泄露 memory leak:是指程序在申请内存后无法释放已申请的内存空间,一次内存泄露危害可以忽略但内存泄露堆积后果很严重,无论多少内存,迟早会被占光

一、Handler 引起的内存泄漏

解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用其生命周期就和外部类无关,

如果Handler里面需要context的话可以通过弱引用方式引用外部类

二、单例模式引起的内存泄漏。

三、非静态内部類创建静态实例引起的内存泄漏

解决:把内部类修改为静态的就可以避免内存泄漏了

四、非静态匿名内部类引起的内存泄漏。

解决:将匿名内部类设置为静态的

五、注册/反注册未成对使用引起的内存泄漏。

注册广播接受器、EventBus等记得解绑。

六、资源对象没有关闭引起的內存泄漏

在这些资源不使用的时候,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放

七、集合对象没有及时清理引起的内存泄漏。

通常会把一些对象装入到集合中当不使用的时候一定要记得及时清理集合,让相关对象不再被引用

图片资源,不同图片的的分辨率放在相应的文件夹下可使用百分比代替。

App启动优化(针对冷启动)

App启动的方式有三种:

冷启动:App没有启动过或App进程被killed, 系统中不存在该App进程, 此时启动App即为冷启动

热启动:热启动意味着你的App进程只是处于后台, 系统只是将其从后台带到前台接待员, 展示给用户。

介于冷启动和热啟动之间, 一般来说在以下两种情况下发生:

(1)过于复杂的布局.

(2)UI线程的复杂运算

(3)频繁的GC,导致频繁GC有两个原因:1、内存抖动, 即大量的对象被创建又在短时间内马上被释放.2、瞬间产生大量的对象会严重占用内存区域

内存优化:参考内存泄露和内存溢出部分

(2)定位中使用GPS, 请记得及时关闭

API设計:App与Server之间的API设计要考虑网络请求的频次, 资源的状态等. 以便App可以以较少的请求来完成业务需求和界面的展示.

图片的Size:可以在获取图片时告知服务器需要的图片的宽高, 以便服务器给出合适的图片, 避免浪费.

网络缓存:适当的缓存, 既可以让我们的应用看起来更快, 也能避免一些不必偠的流量消耗.

最终都是通过java层的createBitmap来完成的,需要消耗更多内存.

(2)图片进行缩放的比例SDK中建议其值是2的指数值,值越大会导致图片不清晰。

(3)不鼡的图片记得调用图片的recycle()方法

1. 通过WebView的loadUrl(),使用该方法比较简洁方便。但是效率比较低获取返回值比较困难。

2. 通过WebView的evaluateJavascript(),该方法效率高但是4.4以仩的版本才支持,4.4以下版本不支持所以建议两者混合使用。

1. 通过WebView的addJavascriptInterface()进行对象映射 该方法使用简单,仅将Android对象和JS对象映射即可但昰存在比较大的漏洞。

漏洞产生原因是:当JS拿到Android这个对象后就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类)从而进行任意代码執行。

(3)如果检测到是预先约定好的协议就调用相应方法

这种方式的优点:不存在方式1的漏洞;缺点:JS获取Android方法的返回值复杂。

垃圾收集算法的核心思想是:对虚拟机可用内存空间即堆空间中的对象进行识别,如果对象正在被引用那么称其为存活对象

,反之如果对象鈈再被引用,则为垃圾对象可以回收其占据的空间,用于再分配垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能。

(1)5s内无法响应用户输入事件(例如键盘输入, 触摸屏幕等).

(1)不要在主线程中做耗时的操作而应放在子线程中来实现。如onCreate()和onResume()里尽可能少的去莋创建操作

(3)避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面并从当前用户正在运行的程序上抢夺焦点。

(4)service是运行在主线程的所以在service中莋耗时操作,必须要放在子线程中

此处延伸:Double Check的写法被要求写出来。

单例模式:分为恶汉式和懒汉式

此处延伸:手写mvp例子与mvc之间的区別,mvp的优势

MVP模式对应着Model--业务逻辑和实体模型,view--对应着activity,负责View的绘制以及与用户交互,Presenter--负责View和Model之间的交互,MVP模式是在MVC模式的基础上将Model与View彻底分離使得项目的耦合性更低,在Mvc中项目中的activity对应着mvc中的C--Controllor,而项目中的逻辑处理都是在这个C中处理同时View与Model之间的交互,也是也就是说mvc中所有嘚逻辑交互和用户交互,都是放在Controllor中也就是activity中。View和model是可以直接通信的而MVP模式则是分离的更加彻底,分工更加明确Model--业务逻辑和实体模型view--负责与用户交互,Presenter 负责完成View于Model间的交互MVP和MVC最大的区别是MVC中是允许Model和View进行交互的,而MVP中很明显Model与View之间的交互由Presenter完成。还有一点就是Presenter与Viewの间的交互是通过接口的

31、手写算法(选择冒泡必须要会)

(5)将动态链接库复制到java工程在java工程中调用,运行java工程即可

RecyclerView可以完成ListView,GridView的效果还鈳以完成瀑布流的效果。同时还可以设置列表的滚动方向(垂直或者水平);

RecyclerView中view的复用不需要开发者自己写代码系统已经帮封装完成了。

如果需要频繁的刷新数据需要添加动画,则RecyclerView有较大的优势

如果只是作为列表展示,则两者区别并不是很大

Fresco 是 Facebook 推出的开源图片缓存笁具,主要特点包括:两个内存缓存加上 Native 缓存构成了三级缓存

1. 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间緩冲数据也存放在本地堆内存, 所以, 应用程序有更多的内存使用, 不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收 Bitmap 导致的界面卡頓, 性能更高。

2. 渐进式加载 JPEG 图片, 支持图片从模糊到清晰加载

3. 图片可以以任意的中心点显示在 ImageView, 而不仅仅是图片的中心。

4. JPEG 图片改变大小也是在 native 進行的, 不是在虚拟机的堆内存, 同样减少 OOM

5. 很好的支持 GIF 图片的显示。

3.默认实现多种内存缓存算法 这几个图片缓存都可以配置缓存算法不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等

4.支持本地缓存文件名规则萣义

1. 自带统计监控功能。支持图片缓存使用的监控包括缓存命中率、已使用内存大小、节省的流量等。

2.支持优先级处理每次任务调度湔会选择优先级高的任务,比如 App 页面中 Banner 的优先级高于 Icon 时就很适用

3.支持延迟到图片尺寸计算完成加载

4.支持飞行模式、并发线程数根据网络類型而变。 手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数比如 wifi 最大并发为 4,4g 为 33g 为 2。 这里 Picasso 根据网络类型来决定最夶并发数而不是 CPU 核数。

5.“无”本地缓存无”本地缓存,不是说没有本地缓存而是 Picasso 自己没有实现,交给了 Square 的另外一个网络库 okhttp 去实现這样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。

1. 不仅仅可以进行图片缓存还可以缓存媒体文件Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图甚至是 Video,所以更该当做一个媒体缓存

2. 支持优先级处理。

5. 内存友好Glide 的内存缓存有个 active 的设计,从内存缓存中取数据时不像一般的实现用 get,而是用 remove再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数在图片加载完成后进行判断,如果引用计数为空则回收掉内存缓存更小图片,Glide 以 url、view_width、view_height、屏幕的分辨率等做为联合 key将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小与 Activity/Fragment 生命周期┅致支持 trimMemory。图片默认使用默认 RGB_565 而不是 ARGB_888虽然清晰度差些,但图片更小也可配置到 ARGB_888。

Xutils这个框架非常全面可以进行网络请求,可以进行圖片加载处理可以数据储存,还可以对view进行注解使用这个框架非常方便,但是缺点也是非常明显的使用这个项目,会导致项目对这個框架依赖非常的严重一旦这个框架出现问题,那么对项目来说影响非常大的、

OKhttp:Android开发中是可以直接使用现成的api进行网络请求的。就昰使用HttpClient,HttpUrlConnection进行操作okhttp针对Java和Android程序,封装的一个高性能的http请求库支持同步,异步而且okhttp又封装了线程池,封装了数据转换封装了参数的使鼡,错误处理等API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装这样才能使用的更加的顺手。

甚至支歭OkHttp而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用稍复杂点的需求还是需要用到专门的图片加载框架。Volley也有缺陷比如不支持post大数据,所以不适合上传文件不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生。

Retrofit:Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架RESTful是目前流行的一套api设计的风格, 並不是标准Retrofit的封装可以说是很强大,里面涉及到一堆的设计模式,可以通过注解直接配置请求可以使用不同的http客户端,虽然默认是用http 鈳以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持使用Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛

Volley的优势在于封装的更恏,而使用OkHttp你需要有足够的能力再进行一次封装而OkHttp的优势在于性能更高,因为 OkHttp基于NIO和Okio 所以性能上要比 Volley更快。IO 和 NIO这两个都是Java中的概念洳果我从硬盘读取数据,第一种方式就是程序一直等数据读完后才能继续操作这种是最简单的也叫阻塞式IO,还有一种是你读你的,程序接着往下执行,等数据处理完你再来通知我然后再处理回调。而第二种就是 NIO 的方式非阻塞式, 所以NIO当然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基础上做的一个更简单、高效处理数据流的一个库理论上如果Volley和OkHttp对比的话,更倾向于使用 Volley因为Volley内部同样支持使用OkHttp,这点OkHttp的性能优势就没叻, 而且 Volley 本身封装的也更易用扩展性更好些。

毫无疑问Retrofit 默认是基于 OkHttp 而做的封装,这点来说没有可比性肯定首选 Retrofit。

这两个库都做了不錯的封装但Retrofit解耦的更彻底,尤其Retrofit2.0出来,Jake对之前1.0设计不合理的地方做了大量重构 职责更细分,而且Retrofit默认使用OkHttp,性能上也要比Volley占优势再有如果你的项目如果采用了RxJava ,那更该使用 Retrofit 所以这两个库相比,Retrofit更有优势在能掌握两个框架的前提下该优先使用 Retrofit。但是Retrofit门槛要比Volley稍高些要悝解他的原理,各种用法想彻底搞明白还是需要花些功夫的,如果你对它一知半解那还是建议在商业项目使用Volley吧。

(2)sleep方法没有释放锁洏wait方法释放了锁。

(3)wait,notify,notifyAll只能在同步控制方法或者同步控制块里面使用而sleep可以在任何地方使用。

start()方法是用来启动新创建的线程而start()内部调用了run()方法,这和直接调用run()方法是不一样的如果直接调用run()方法,

则和普通的方法没有什么区别

1、final变量即为常量,只能赋值一次

2、final方法不能被子类重写。

3、final类不能被继承

1、static变量:对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存

在加载类的过程中唍成静态变量的内存分配,可用类名直接访问(方便)当然也可以通过对象来访问(但是这是不推荐的)。

static代码块是类加载时初始化洎动执行的。

static方法可以直接通过类名调用任何的实例也都可以调用,因此static方法中不能用this和super关键字

不能直接访问所属类的实例变量和实唎方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法

5、Java中重载和重写的区别:

1、重载:一个类中可鉯有多个相同方法名的,但是参数类型和个数都不一样这是重载。

2、重写:子类继承父类则子类可以通过实现父类中的方法,从而新嘚方法把父类旧的方法覆盖

此处延伸:https的实现原理

1、https协议需要到ca申请证书,一般免费证书较少因而需要一定费用。

2、http是超文本传输协議信息是明文传输,https则是具有安全性的ssl加密传输协议

3、http和https使用的是完全不同的连接方式,用的端口也不一样前者是80,后者是443

4、http的連接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议比http协议安全。

(1)客户使用https的URL访问Web服务器要求與Web服务器建立SSL连接。

(2)Web服务器收到客户端请求后会将网站的证书信息(证书中包含公钥)传送一份给客户端。

(3)客户端的浏览器与Web垺务器开始协商SSL连接的安全等级也就是信息加密的等级。

(4)客户端的浏览器根据双方同意的安全等级建立会话密钥,然后利用网站嘚公钥将会话密钥加密并传送给网站。

(5)Web服务器利用自己的私钥解密出会话密钥

(6)Web服务器利用会话密钥加密与客户端之间的通信。

7、Http位于TCP/IP模型中的第几层为什么说Http是可靠的数据传输协议?

从下到上:物理层->数据链路层->网络层->传输层->应用层

其中tcp/ip位于模型中的网络层处于同一层的还有ICMP(网络控制信息协议)。http位于模型中的应用层

由于tcp/ip是面向连接的可靠协议而http是在传输层基于tcp/ip协议的,所以说http是可靠嘚数据传输协议

8、HTTP链接的特点

HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后会主动释放连接。

从建立连接到关闭连接的过程称为“一次连接”

tcp是面向连接的,由于tcp连接需要三次握手所以能够最低限度的降低风险,保证连接的可靠性

udp 不是面向连接的,udp建立连接前不需要与对象建立连接无论是发送还是接收,都没有发送确认信号所以说udp是不可靠的。

由于udp不需要進行确认连接使得UDP的开销更小,传输速率更高所以实时行更好。

10、Socket建立网络连接的步骤

1、服务器监听:服务器端套接字并不定位具体嘚客户端套接字而是处于等待连接的状态,实时监控网络状态等待客户端的连接请求。

2、客户端请求:指客户端的套接字提出连接请求要连接的目标是服务器端的套接字。注意:客户端的套接字必须描述他要连接的服务器的套接字

指出服务器套接字的地址和端口号,然后就像服务器端套接字提出连接请求

3、连接确认:当服务器端套接字监听到客户端套接字的连接请求时,就响应客户端套接字的请求建立一个新的线程,把服务器端套接字的描述

发给客户端一旦客户端确认了此描述,双方就正式建立连接而服务端套接字则继续處于监听状态,继续接收其他客户端套接字的连接请求

完整版面试题和学习笔记整理在石墨文档可见

这是上一篇,无先后顺序;

如果囿帮助可以点个关注,第一时间分享Android最新技术和进阶资料~

前几天整理了,今天再来整理下Android相關的面试题集合.假设你希望能得到最新的消息,能够关注,我会不断的添加和修正相关问题的描写叙述.

介绍不同场景下Activity生命周期的变化过程

  • 锁定屏与解锁屏幕 仅仅会调用onPause()而不会调用onStop方法,开屏后则调用onResume()

Asynctask为什么要设置为仅仅能够一次任务

若Activity已经销毁,此时AsynTask运行完并返回结果,会报异常么?

内存鈈足时,系统会杀死后台的Activity,假设须要进行一些暂时状态的保存,在哪个方法进行

可是当用户主动去销毁一个Activity时比如在应用中按返回键,onSaveInstanceState()就不會被调用除非该activity是被用户主动销毁的,通常onSaveInstanceState()仅仅适合用于保存一些暂时性的状态而onPause()适合用于数据的持久化保存。

standard启动模式無论有没有已存在的实例,都生成新的实例

跳转时系统会先在栈结构中寻找是否有一个Activity实例正位于栈顶。假设有则不再生成新的而是矗接使用。假设系统发现存在有Activity实例,但不是位于栈顶又一次生成一个实例。 这就是singleTop启动模式假设发现有对应的Activity实例正位于栈顶。则反複利用不再生成新的实例。
4. singleInstance 这样的启动模式比較特殊由于它会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中并保证不再有其它Activity實例进入。

  1. singleTop适合接收通知启动的内容显示页面


    比如,某个新闻client的新闻内容页面假设收到10个新闻推送,每次都打开一个新闻内嫆页面是非常烦人的

  2. 比如浏览器的主界面。无论从多少个应用启动浏览器仅仅会启动主界面一次,其余情况都会走onNewIntent而且会清空主界媔上面的其它页面。

    你以前设置了一个闹铃:上午6点在上午5点58分,你启动了闹铃设置界面并按 Home 键回桌面;在上午5点59分时,你在微信和萠友聊天;在6点时闹铃响了,而且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 载入模式打开的)你按返回键,回到的是微信嘚聊天界面这是由于 AlarmAlertActivity 所在的 Task 的栈仅仅有他一个元素, 因此退出之后这个 Task 的栈空了

    假设是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候按返回键应該进入闹铃设置界面。

怎样把一个应用设置为系统应用

  1. 假设是非root设备,须要编译后烧写镜像
  2. 有些权限(如WRITE_SECURE_SETTINGS)不开放给第三方应用,仅仅能在对应设备源代码总编译然后作为系统app使用

Activity像一个工匠(控制单元)Window像窗户(承载模型),View像窗花(显示视图) LayoutInflater像剪刀Xml配置像窗花图纸。

Android两个应用能在同一个任务栈吗

栈一般以包名命名,两个应用的签名和udid要同样

在Activity中能够加入,删除,替换Fragment.Fragment能够响应自己的输入时间,而且有自己的生命周期,泹其生命周期收Activity影响.

怎样实现Activity窗体高速变暗

是否使用過本地广播,和全局广播有什么差别?

本地广播在本应用范围内传播,不用操心隐私数据泄露,不用操心别的应用伪造广播.相比全局广播,本地广播哽高效.

1.静态注冊:在清单文件里注冊 常见的有监听设备启动,常驻注冊不会随程序生命周期改变
2.动态注冊:在代码中注冊随着程序的结束。也就停止接受广播了

补充一点:有些广播仅仅能通过动态方式注冊比方时间变化事件、屏幕亮灭事件、电量变更倳件,由于这些事件触发频率通常非常高假设同意后台监听。会导致进程频繁创建和销毁从而影响系统总体性能

為什么Android引入广播机制?

a:从MVC的角度考虑(应用程序内) 事实上回答这个问题的时候还能够这样问,android为什么要有那4大组件如今的移动开发模型基夲上也是照搬的web那一套MVC架构。仅仅只是是改了点嫁妆而已android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有時候是一种相互依存的关系有时候又是一种补充关系。引入广播机制能够方便几大组件的信息和数据交互
b:程序间互通消息(比如在自巳的应用程序内监听系统来电)
c:效率上(參考UDP的广播协议在局域网的方便性)
d:设计模式上(反转控制的一种应用。相似监听者模式)

IntentService是Service的子类是一个异步的。会自己主动停止的服务非常好攻克了传统的Service中处理完耗时操作忘记停止并销毁Service的问题

串行队列,每次僅仅运行一个任务,不存在线程安全问题,全部任务运行完后自己主动停止服务,不须要自己手动调用stopSelf()来停止.

介绍Android下的数据存储方式

当一个应用程序须要把自己的数据暴露给其它程序使用时,该就用程序就可通过提供ContentProvider来实现;其它应用程序就可通过ContentResolver来操作ContentProvider暴露的数据 一旦某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么无论该应用程序是否启动其它应用程序都能够通过该接口来操作该应用程序的内部数据,包含添加数据、删除数据、改动数据、查询数据等

而sql的能够理解为数据库的一门语言,能够使用它完毕CRUD等一系列的操作

  • SharedPreferences是一种轻量级的数据存储机制他将一些简单的数據类型的数据。包含boolean类型int类型。float类型long类型以及String类型的数据,以键值对的形式存储在应用程序的私有Preferences文件夹(/data/data/<包名>/shared_prefs/)中这样的Preferences机制广泛应用于存储应用程序中的配置信息。

  • SQLite数据库: 当应用程序须要处理的数据量比較大时为了更加合理地存储、管理、查询数据。我们往往使用关系数据库来存储数据Android系统的非常多用户数据,如联系人信息通话记录,短信息等都是存储在SQLite数据库其中的,所以利用操作SQLite數据库的API能够同样方便的訪问和改动这些数据

  • ContentProvider: 主要用于在不同的应用程序之间实现数据共享的功能,不同于sharepreference和文件存储中的两种全局可讀写操作模式内容提供其能够选择仅仅对哪一部分数据进行共享。从而保证我们程序中的隐私数据不会有泄漏的风险

怎样将打开res aw文件夹中的数据库文件?

在Android中不能直接打开res aw文件夹中的数据库文件而须要在程序第一次启動时将该文件拷贝到手机内存或SD卡的某个文件夹中。然后再打开该数据库文件

一条最长的短信息约占多少byte?

中攵70(包含标点),英文160160个字节。


jar打包不能包含资源文件比方一些drawable文件、xml资源文件之类的,aar能够。

加入删除怎样提高性能?

SQLite作为轻量级的数据库比MySQL还小,但支持SQL语句查询提高性能能够考虑通过原始经过优化的SQL查询語句方式处理

能够将dictionary.db文件拷贝到Eclipse Android工程中的res aw文件夹中。全部在res aw文件夹中的文件不会被压缩这样能够矗接提取该文件夹中的文件。能够将dictionary.db文件拷贝到res aw文件夹中

  1. 通过 startForeground将进程设置为前台接待员进程 做前台接待员服务,优先级和前台接待员应用一个级别?除非在系统内存非常缺。否则此进程不会被 kill

  2. 双进程Service: 让2个进程互相保护**其中一个Service被清理后。另外没被清理的进程能够马上重新启动进程

  3. QQ黑科技: 在应用退到后台后另起一个仅仅有 1 像素的页面停留在桌面上。让自己保持前囼接待员状态保护自己不被后台清理工具杀死

  4. 在已经root的设备下,改动对应的权限文件,将App伪装成系统级的应用 Android4.0系列的一个漏洞已经确认鈳行

  5. 用C编写守护进程(即子进程) : Android系统中当前进程(Process)fork出来的子进程。被系统觉得是两个不同的进程

    当父进程被杀死的时候。子进程仍然能够存活并不受影响。鉴于眼下提到的在Android->- Service层做双守护都会失败我们能够fork出c进程。多进程守护

    死循环在那检查是否还存在,详细的思路例如鉯下(Android5.0以上的版本号不可行)

  6. 用C编写守护进程(即子进程)守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它
  7. 在NDK环境中將1中编写的C代码编译打包成可运行文件(BUILD_EXECUTABLE)。主进程启动时将守护进程放入私有文件夹下赋予可运行权限,启动它就可以

Android中怎样获得手机的唯一标示.

1 首先尝试读取IMEI、Mac地址、CPU号等物理信息(有不少工具能够改动IMEI);
2 假设均失敗,能够自己生成UUID然后保存到文件(文件也可能被篡改或删除)

Android应用中验证码登录都有哪些实现方案

驗证码应该仅仅有两种获取方式: 从server端获取图片 通过短信服务,将验证码发送给client这两种

为什么要设计Bundle而不昰直接使用Map?

Android中XML解析方式的比較急优缺点

SAX解析器的优点是解析速度快占用内存少;
DOM在内存中以树形结构存放,洇此检索和更新效率会更高

可是对于特别大的文档。解析和载入整个文档将会非常耗资源不适合移动端;
PULL解析器的运行方式和SAX相似。嘟是基于事件的模式PULL解析器小巧轻便。解析速度快简单易用。非常适合在Android移动设备中使用Android系统内部在解析各种XML时也是用PULL解析器。


而之所以给开发人员默认新建了个RelativeLayout是希望开发人员能採用尽量少的View层级来表达布局以实现性能最优由于复杂的View嵌套对性能的影響会更大一些。

  • 当我们在画布局的时候假设能实现同样的功能。优先考虑相对布局然后在考虑别的布局,不要用绝对布局
  • 使用<merge />标签,由于它在优化UI结构时起到非常关键的数据

    目的是通过删减多餘或者额外的层级。从而优化整个Android Layout的结构核心功能就是降低冗余的层次从而达到优化UI的目的!

  • ViewStub 是一个隐藏的。不占用内存空间的视图对潒它能够在运行时延迟载入布局资源文件。

它仅仅是用来放启动图标的,优点就是你仅仅用放一个mipmap图标。它就会給你各种版本号(比方平板手机)的apk自己主动生成对应分辨率的图标。以节约空间

ListView卡顿的原因以及优化策略

  • 偅用converView: 通过复用converview来降低不必要的view的创建。另外Infalte操作会把xml文件实例化成对应的View实例属于IO操作。是耗时操作

  • 避免在 getView 方法中做耗时的操作: 比洳载入本地 Image 须要载入内存以及解析 Bitmap ,都是比較耗时的操作假设用户高速滑动listview,会由于getview逻辑过于复杂耗时而造成滑动卡顿现象用户滑动時候不要载入图片。待滑动完毕再载入能够使用这个第三方库

  • Item的布局层次结构尽量简单,避免布局太深或者不必要的重绘

  • 在一些场景中ScollView内会包含多个ListView。能够把listview的高度写死固定下来

    由于ScollView在高速滑动过程中须要大量计算每一个listview的高度,堵塞了UI线程导致卡顿现象出现假设峩们每一个item的高度都是均匀的,能够通过计算把listview的高度确定下来避免卡顿现象出现

  • RecycleView能够实现当个item的局部刷新。而且引入了添加和删除的動态效果在性能上和定制上都有非常大的改善

  • ListView 中元素避免半透明: 半透明绘制须要大量乘法计算,在滑动时不停重绘会造成大量的计算在比較差的机子上会比較卡。 在设计上能不半透明就不不半透明实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再又一次設置成半透明

  • 尽量开启硬件加速: 硬件加速提升巨大,避免使用一些不支持的函数导致含泪关闭某个地方的硬件加速当然这一条不仅僅是对 ListView。

怎样实现一个局部更新的ListView

ViewHolder为什么要被声明成静态内部类

這个是考静态内部类和非静态内部类的主要差别之中的一个

非静态内部类会隐式持有外部类的引用,就像大家常常将自己定义的adapter在Activity类里然后在adapter类里面是能够随意调用外部activity的方法的。

当你将内部类定义为static时你就调用不了外部类的实例方法了,由于这时候静态内部类是不歭有外部类的引用的声明ViewHolder静态内部类,能够将ViewHolder和外部类解引用大家会说一般ViewHolder都非常简单,不定义为static也没事吧确实如此,可是假设你將它定义为static的说明你懂这些含义。万一有一天你在这个ViewHolder加入一些复杂逻辑做了一些耗时工作,那么假设ViewHolder是非静态内部类的话就非常easy絀现内存泄露。假设是静态的话你就不能直接引用外部类,迫使你关注怎样避免相互引用 所以将 ViewHolder内部类 定义为静态的,是一种好习惯


有哪些进程通信的方式?

AIDL 体现了哪些设计思想

非常多人吧Binder的原理解释的非常复杂,让人看着就头大,可是熟悉Linux开发的小伙伴能够一下想到Binder驱动本质就是文件,实现採用了代理而已.详细看下图:

  • Handler通过调用sendmessage方法把消息放茬消息队列MessageQueue中Looper负责把消息从消息队列中取出来,又一次再交给Handler进行处理三者形成一个循环
  • 通过构建一个消息队列,把全部的Message进行统一嘚管理当Message不用了,并不作为垃圾回收而是放入消息队列中。供下次handler创建消息时候使用提高了消息对象的复用,降低系统垃圾回收的佽数
  • 每一个线程都会单独对应的一个looper,这个looper通过ThreadLocal来创建保证每一个线程仅仅创建一个looper,looper初始化后就会调用looper.loop创建一个MessageQueue这种方法在UI线程初始化的时候就会完毕,我们不须要手动创建

  • 逐帧动画(Drawable Animation): 载入一系列Drawable资源来创建动画简单来说就是播放一系列的图片来實现动画效果,能够自己定义每张图片的持续时间

  • 补间动画(Tween Animation): Tween能够对View对象实现一系列简单的动画效果比方位移,缩放旋转。透明度等等可是它并不会改变View属性的值。仅仅是改变了View的绘制的位置比方,一个button在动画过后不在原来的位置。可是触发点击事件的仍然是原來的坐标

  • 属性动画(Property Animation): 动画的对象除了传统的View对象。还能够是Object对象动画结束后。Object对象的属性值被实实在在的改变了

Animation框架定义了透明度旋转,缩放和位移几种常见的动画而且控制的是整个View,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值然后调用canvas.concat(transformToApply.getMatrix())。通过矩阵运算完毕动画帧假设动画没有完毕,继续调用invalidate()函数启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间可能会导致动画消耗比較多的CPU资源,最重要的是动画改变的仅仅是显示。并不能对应事件

假设你的需求中仅仅須要对View进行移动、缩放、旋转和淡入淡出操作那么补间动画确实已经足够健全了。可是非常显然这些功能是不足以覆盖全部的场景的,一旦我们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操作那么补间动画就不能再帮我们忙了。也就是说它在功能和可扩展方面都有相当大的局限性那么以下我们就来看看补间动画所不能胜任的场景。


注意上面我在介绍补间动画的时候都有使用“对View进行操作”这样的描写叙述没错,补间动画是仅仅能够作用在View上的也就是说,我们能够对一个Button、TextView、甚至是LinearLayout、或者其它不论什么继承自View的组件进荇动画操作可是假设我们想要对一个非View的对象进行动画操作,抱歉补间动画就帮不上忙了。可能有的朋友会感到不能理解我怎么会須要对一个非View的对象进行动画操作呢?这里我举一个简单的样例比方说我们有一个自己定义的View,在这个View其中有一个Point对象用于管理坐标嘫后在onDraw()方法其中就是依据这个Point对象的坐标值来进行绘制的。也就是说假设我们能够对Point对象进行动画操作,那么整个自己定义View的动画效果僦有了显然。补间动画是不具备这个功能的这是它的第一个缺陷。


然后补间动画另一个缺陷就是它仅仅能够实现移动、缩放、旋转囷淡入淡出这四种动画操作。那假设我们希望能够对View的背景色进行动态地改变呢非常遗憾。我们仅仅能靠自己去实现了说白了。之前嘚补间动画机制就是使用硬编码的方式来完毕的功能限定死就是这些,基本上没有不论什么扩展性可言


最后,补间动画另一个致命的缺陷就是它仅仅是改变了View的显示效果而已,而不会真正去改变View的属性什么意思呢?比方说如今屏幕的左上角有一个button,然后我们通过補间动画将它移动到了屏幕的右下角如今你能够去尝试点击一下这个button,点击事件是绝对不会触发的由于实际上这个button还是停留在屏幕的咗上角,仅仅只是补间动画将这个button绘制到了屏幕的右下角而已


SurfaceView中採用了双缓存技术,在单独的线程中更新界面
View在UI线程中更新界媔

介绍下自己定义view的基本流程

  1. 明白需求确定你想实现的效果
  2. 确定是使用组合控件的形式还是全新自己定义的形式,组合控件即使用多个系统控件来合成一个新控件你比方titilebar,这样的形式相对简单參考
  3. 假设是全然自己定义一个view的话,你首先须要栲虑继承哪个类是View呢,还是ImageView等子类
  4. 依据须要为你的自己定义view提供自己定义属性。即编写attr.xml,然后在代码中通过TypedArray等类获取到自己定义属性值 7.須要处理滑动冲突、像素转换等问题

谈谈View的绘制流程


measure()方法layout(),draw()三个方法主要存放了一些标识符来推断每一个View是否须要再叒一次測量。布局或者绘制基本的绘制过程还是在onMeasure,onLayoutonDraw这个三个方法中

2.onLayout() 为将整个依据子视图的大小以及布局參数将View树放到合适的位置上。

3. onDraw() 開始绘制图像绘制的流程例如以下

  1. 首先绘制该View的背景
  2. 调用onDraw()方法绘制视图本身 (每一个View都须要重载该方法,ViewGroup不须要实现该方法)
  1. 自己定义一個view时重写onDraw。

怎样实现一个字体的描边与阴影效果


谈谈touch事件的传递流程

  1. 假设事件从上往下传递过程中一直没有被停止且最底层子View没有消费事件,事件会反向往上传递这时父View(ViewGroup)能够进行消费,假设还是没有被消费的话最后会到Activity的onTouchEvent()函数。

  2. 假设View没有对ACTION_DOWN进行消费之后的其它事件不会传递过来。

Android下滑冲突嘚常见解决思路

相关的滑动组件 重写onInterceptTouchEvent然后推断依据xy值。来决定是否要拦截当前操作


Bitmap是android中常常使用的一个類它代表了一个图片资源。

Bitmap消耗内存非常严重假设不注意优化代码,常常会出现OOM问题优化方式通常有这么几种: 1. 使用缓存; 2. 压缩图爿; 3. 及时回收。

至于什么时候须要手动调用recycle这就看详细场景了,原则是当我们不再使用Bitmap时须要回收。

另外我们须要注意,2.3之前Bitmap对象與像素数据是分开存放的Bitmap对象存在java Heap中而像素数据存放在Native Memory中,这时非常有必要调用recycle回收内存可是2.3之后,Bitmap对象和像素数据都是存在Heap中GC能夠回收其内存。


JAVA反射机制是在#运行时#对于随意一个类。都能够知道这个类的全部属性和方法;对于随意一个对象嘟能够调用它的随意一个方法;这样的动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

Java反射机制主要提供了以下功能: a)在运行时推断随意一个对象所属的类; b)在运行时构造随意一个类的对象; c)在运行时推断随意一个类所具有的成员变量和方法 d)在运行時调用随意一个对象的方法。生成动态代理

你以前利用反射做过什么?


NDK是一些列工具的集合。
NDK提供了一系列的工具帮助开发人员迅速的开发C/C++的动态库,并能自己主动将so和java 应用打成apk包


NDK集成了交叉编译器。并提供了对应的mk文件和隔离cpu、平台等嘚差异开发人员仅仅需简单的改动mk文件就能够创建出so

NDK开发须要注意什么?

  1. 实现JNI原生函数源文件。新建HelloWorld.c文件对刚才自己主动生成的函数进行详细的逻辑书写,比如返回一个java叫做HelloWorld的字符串等
  2. 编译生成动态链接so文件**


移动端获取数据优化的几个点

    即将多个请求合并为一个进行请求比較常见的就是网页中的 CSS Image Sprites。

    假设某个页面内请求过多也能够考虑做一定的请求合并。

  1. 返回的数据的body也能够作gzip压缩body数据体积能够缩小到原来的30%左右。

    (也能够考虑压縮返回的json数据的key数据的体积尤其是针对返回数据格式变化不大的情况,支付宝聊天返回的数据用到了)

  2. 依据用户的当前的网络质量来推断丅载什么质量的图片(电商用的比較多)

怎样设计一个良好的网络层?

怎样防止反复发送网络请求

点击activity上的一个button,发送网络请求在网络比較慢的情况下。用户可能会继续去点击button这个时候,发送其它无谓的请求不知道大镓是怎么处理这类问题来拦截?
HTTP header中加入max-age这样某个固定的时间内都将返回empty body,当然这种方法是死的把时间全然限制了,这种方法回掉也会哃样要运行多次
还有个晕招,就是直接设置button的clickable为false或者使用progressbar。相似于楼主的方法比方点赞的场景。


使用Map的话在回掉的时候,还是须偠回收HashMap的维护Map还不如仅仅维护一个boolean呢。
Volley中假设开了缓存的话, 同样的请求同一时候仅仅会有一个去真正的请求, 兴许都走缓存, 尽管不会请求哆次, 可是回调是会运行多次的, 和这个需求不match


怎样调试Android应用程序

Android中常常使用的測试工具?


  1. 资源对象没有关闭造成,如查询数据库没有关闭游标
  2. 集合对象未清理,如无用时没有释放对象的引用
  3. 在Activity中使用非静态的内部类并开启一个长时间运行的线程,由于内部类持有Activity的引用会导致Activity本来能够被gc时却长期得不到回收

  • 类的静态变量持有大数據对象 静态变量长期维持到大数据对象的引用,阻止垃圾回收

  • 非静态内部类存在静态实例 非静态内部类会维持一个到外部类实例的引用,假设非静态内部类的实例是静态的就会间接长期维持着外部类的引用,阻止被回收掉

  • 资源对象未关闭 资源性对象比方(Cursor,File文件等)往往都用了一些缓冲我们在不使用的时候,应该及时关闭它们 以便它们的缓冲及时回收内存。它们的缓冲不仅存在于java虚拟机内还存茬于java虚拟机外。

    假设我们仅仅是把它的引用设置为null,而不关闭它们往往会造成内存泄露。 解决的方法: 比方SQLiteCursor(在析构函数finalize(),假设我们没囿关闭它它自己会调close()关闭), 假设我们没有关闭它系统在回收它时也会关闭它。可是这样的效率太低了 因此对于资源性对象在不使鼡的时候。应该调用它的close()函数将其关闭掉,然后才置为null. 在我们的程序退出时一定要确保我们的资源性对象已经关闭 程序中常常会进行查询数据库的操作。可是常常会有使用完毕Cursor后没有关闭的情况

    假设我们的查询结果集比較小, 对内存的消耗不easy被发现仅仅有在常时间夶量操作的情况下才会复现内存问题。这样就会给以后的測试和问题排查带来困难和风险记得try catch后,在finally方法中关闭连接

  • Handler内存泄漏 Handler作为内部類存在于Activity中可是Handler生命周期与Activity生命周期往往并非同样的。比方当Handler对象有Message在排队则无法释放,进而导致本该释放的Acitivity也没有办法进行回收

    • 聲明handler为static类,这样内部类就不再持有外部类的引用了就不会堵塞Activity的释放
    • 假设内部类实在须要用到外部类的对象,可在其内部声明一个弱引鼡引用外部类

一些不良代码习惯 有些代码并不造成内存泄露可是他们的资源没有得到重用,频繁的申请内存和销毁内存消耗CPU资源的同┅时候,也引起内存抖动 解决方式 假设须要频繁的申请内存对象和和释放对象能够考虑使用对象池来添加对象的复用。 比如ListView便是採用这樣的思想通过复用converview来避免频繁的GC

1. 使用更加轻量的数据结构 比如,我们能够考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构通常的HashMap的實现方式更加消耗内存。由于它须要一个额外的实例对象来记录Mapping操作

另外。SparseArray更加高效在于他们避免了对key与value的自己主动装箱(autoboxing)。而且避免了装箱后的解箱

Android.”,详细原理请參考《Android性能优化典范(三)》所以请避免在Android里面使用到枚举。

3. 减小Bitmap对象的内存占用 Bitmap是一个极easy消耗內存的大胖子减小创建出来的Bitmap的内存占用可谓是重中之重。通常来说有以下2个措施: inSampleSize:缩放比例。在把图片载入内存之前我们须要先计算出一个合适的缩放比例,避免不必要的大图载入

4.Bitmap对象的复用 缩小Bitmap的同一时候。也须要提高BitMap对象的复用率避免频繁创建BitMap对象,复鼡的方法有以下2个措施 LRUCache : “近期最少使用算法”在Android中有极其普遍的应用ListView与GridView等显示大量图片的控件里,就是使用LRU的机制来缓存处理好的Bitmap把菦期最少使用的数据从缓存中移除,保留使用最频繁的数据 inBitMap高级特性:利用inBitmap的高级特性提高Android系统在Bitmap分配与释放运行效率。使用inBitmap属性能够告知Bitmap解码器去尝试使用已经存在的内存区域新解码的Bitmap会尝试去使用之前那张Bitmap在Heap中所占领的pixel data内存区域,而不是去问内存又一次申请一块区域來存放Bitmap利用这样的特性,即使是上千张的图片也仅仅会仅仅仅仅须要占用屏幕所能够显示的图片数量的内存大小

在涉及给到资源图片時。我们须要特别留意这张图片是否存在能够压缩的空间能否够使用更小的图片。尽量使用更小的图片不仅能够降低内存的使用还能避免出现大量的InflationException。假设有一张非常大的图片被XML文件直接引用非常有可能在初始化视图时会由于内存不足而发生InflationException,这个问题的根本原因事實上是发生了OOM

5.StringBuilder 在有些时候,代码中会须要使用到大量的字符串拼接的操作这样的时候有必要考虑使用StringBuilder来替代频繁的“+”。

4.避免在onDraw方法裏面运行对象的创建 相似onDraw等频繁调用的方法一定须要注意避免在这里做创建对象的操作,由于他会迅速添加内存的使用而且非常easy引起頻繁的gc。甚至是内存抖动

5. 避免对象的内存泄露 android中内存泄漏的场景以及解决的方法,參考上一问


假设一个应用无法响应用户的输入系统就会弹出一个ANR对话框,用户能够自行选择继续等待亦或者是停止当前程序

一旦出现以下两种情况,则弹出ANR对话框
1. 应用在5秒内未响應用户的输入事件(如按键或者触摸)

Service在特定的时间内无法处理完毕
超时的原因一般有两种:
(1)当前的事件没有机会得到处理(UI线程正在处悝前一个事件没有及时完毕或者looper被某种原因堵塞住)
(2)当前的事件正在处理但没有及时完毕
UI线程尽量仅仅做跟UI相关的工作,耗时的工作(數据库操作I/O,连接网络或者其它可能阻碍UI线程的操作)放入单独的线程处理尽量用Handler来处理UI thread和thread之间的交互。

避免ANR朂核心的一点就是在主线程降低耗时操作.通常须要从以下几个方案下手:

  • 使用子线程处理耗时IO操作


password不要存在本地,一般保存token最基本的要玳码混淆,能够的话加壳防止反编译


它能够支持.dex格式的程序的运行,.dex格式是专为Dalvik设计的一种压缩格式能够降低总体文件尺寸,提高I/O操作的速度适合内存和处理器速度有限的系统

  • Dalvik 基于寄存器,而 JVM 基于栈基于寄存器的虚拟機对于更大的程序来说,在它们编译的时候花费的时间更短。

Android为每一个应用程序分配的内存大尛是多少

怎样解决方法数65k问题?

Android系统启动流程分析

  1. 打开adb shell 然后运行ps命令能够看到首先运行的是init方法!找到init.c这个文件.
  2. 然后走init里面的main方法,在这main方法里面运行mkdir进行创建非常多的文件夹和挂载一些文件夹
  3. 然后回去初始化init.rc这个配置文件!在这个配置文件里面回去启动孵化器这个服务。这个服务会去启动app_process这个文件夹这个文件夹里面有个app_main.cpp这个文件。
  4. 然后在app_main.cpp这个c文件里面在main方法里面咜会去启动安卓的虚拟机然后安卓虚拟机会去启动os.zygoteinit这个服务!
  5. zygoteinit这是个java代码写的,然后我们找到了main方法在这种方法里面我们看到他首先設置虚拟机的最小堆内存为5兆,然后走到preloadclasses()这种方法来载入安卓系统全部的2000多个类通过类载入器载入进来,比方activity,contentx,http,…(事实上没有必要一下孓全部载入下来我们能够等用到的时候在载入也能够!
  6. 然后又走preloadresources()这种方法来预载入安卓中定义好的资源比方颜色,图片系统的id等等。

    都载入了!(事实上这也是不是必需的! )

  7. 然后又走startSystemServer(),这种方法来载入系统的服务。他会先使用natvieJNI去调用C去初始化界面和声音的服务這就是我们为什么先听到声音和界面的原因!
  8. 最后等服务载入完毕后也就启动起来了!

我要回帖

更多关于 前台接待员 的文章

 

随机推荐