【建议收藏】2020年中高级Android大厂面试秘籍,为你保驾护航金三银四,直通大厂(Android基础篇)

前言

成为一名优秀的Android开发,须要一份完备的知识体系,在这里,让咱们一块儿成长为本身所想的那样~。

🔥 A awesome android expert interview questions and answers(continuous updating ...)javascript

从几十份顶级面试仓库和300多篇高质量面经中总结出一份全面成体系化的Android高级面试题集。前端

欢迎来到2020年中高级Android大厂面试秘籍,为你保驾护航金三银四,直通大厂的Android基础篇。java

Android基础面试题 (⭐⭐⭐)


一、什么是ANR 如何避免它?

答:在Android上,若是你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称做应 用程序无响应(ANR:Application NotResponding)对话框。 用户能够选择让程序继续运行,可是,他们在使用你的 应用程序时,并不但愿每次都要处理这个对话框。所以 ,在程序里对响应性能的设计很重要这样,这样系统就不会显 示ANR给用户。android

不一样的组件发生ANR的时间不同,Activity是5秒,BroadCastReceiver是10秒,Service是20秒(均为前台)。git

若是开发机器上出现问题,咱们能够经过查看/data/anr/traces.txt便可,最新的ANR信息在最开始部分。github

  • 主线程被IO操做(从4.0以后网络IO不容许在主线程中)阻塞。
  • 主线程中存在耗时的计算
  • 主线程中错误的操做,好比Thread.wait或者Thread.sleep等 Android系统会监控程序的响应情况,一旦出现下面两种状况,则弹出ANR对话框
  • 应用在5秒内未响应用户的输入事件(如按键或者触摸)
  • BroadcastReceiver未在10秒内完成相关的处理
  • Service在特定的时间内没法处理完成 20秒

修正:web

一、使用AsyncTask处理耗时IO操做。面试

二、使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,不然仍然会下降程序响应,由于默认Thread的优先级和主线程相同。算法

三、使用Handler处理工做线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。shell

四、Activity的onCreate和onResume回调中尽可能避免耗时的代码。 BroadcastReceiver中onReceive代码也要尽可能减小耗时,建议使用IntentService处理。

解决方案:

将全部耗时操做,好比访问网络,Socket通讯,查询大 量SQL 语句,复杂逻辑计算等都放在子线程中去,然 后经过handler.sendMessage、runonUIThread、AsyncTask、RxJava等方式更新UI。不管如何都要确保用户界面的流畅 度。若是耗时操做须要让用户等待,那么能够在界面上显示度条。

深刻回答

二、Activity和Fragment生命周期有哪些?

image

三、横竖屏切换时候Activity的生命周期

不设置Activity的android:configChanges时,切屏会从新回调各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。 设置Activity的android:configChanges=”orientation”时,切屏仍是会调用各个生命周期,切换横竖屏只会执行一次 设置Activity的android:configChanges=”orientation |keyboardHidden”时,切屏不会从新调用各个生命周期,只会执行onConfigurationChanged方法

四、AsyncTask的缺陷和问题,说说他的原理。

AsyncTask是什么?

AsyncTask是一种轻量级的异步任务类,它能够在线程池中执行后台任务,而后把执行的进度和最终结果传递给主线程并在主线程中更新UI。

AsyncTask是一个抽象的泛型类,它提供了Params、Progress和Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台任务的执行进度和类型,而Result则表示后台任务的返回结果的类型,若是AsyncTask不须要传递具体的参数,那么这三个泛型参数能够用Void来代替。

关于线程池:

AsyncTask对应的线程池ThreadPoolExecutor都是进程范围内共享的,且都是static的,因此是Asynctask控制着进程范围内全部的子类实例。因为这个限制的存在,当使用默认线程池时,若是线程数超过线程池的最大容量,线程池就会爆掉(3.0后默认串行执行,不会出现个问题)。针对这种状况,能够尝试自定义线程池,配合Asynctask使用。

关于默认线程池:

AsyncTask里面线程池是一个核心线程数为CPU + 1,最大线程数为CPU * 2 + 1,工做队列长度为128的线程池,线程等待队列的最大等待数为28,可是能够自定义线程池。线程池是由AsyncTask来处理的,线程池容许tasks并行运行,须要注意的是并发状况下数据的一致性问题,新数据可能会被老数据覆盖掉。因此但愿tasks可以串行运行的话,使用SERIAL_EXECUTOR。

AsyncTask在不一样的SDK版本中的区别:

调用AsyncTask的execute方法不能当即执行程序的缘由及改善方案经过查阅官方文档发现,AsyncTask首次引入时,异步任务是在一个独立的线程中顺序的执行,也就是说一次只执行一个任务,不能并行的执行,从1.6开始,AsyncTask引入了线程池,支持同时执行5个异步任务,也就是说只能有5个线程运行,超过的线程只能等待,等待前的线程直到某个执行完了才被调度和运行。换句话说,若是进程中的AsyncTask实例个数超过5个,那么假如前5都运行很长时间的话,那么第6个只能等待机会了。这是AsyncTask的一个限制,并且对于2.3之前的版本没法解决。若是你的应用须要大量的后台线程去执行任务,那么只能放弃使用AsyncTask,本身建立线程池来管理Thread。不得不说,虽然AsyncTask较Thread使用起来方便,可是它最多只能同时运行5个线程,这也大大局限了它的做用,你必需要当心设计你的应用,错开使用AsyncTask时间,尽力作到分时,或者保证数量不会大于5个,否就会遇到上面提到的问题。多是Google意识到了AsynTask的局限性了,从Android 3.0开始对AsyncTask的API作出了一些调整:每次只启动一个线程执行一个任务,完了以后再执行第二个任务,也就是至关于只有一个后台线程在执行所提交的任务。

一些问题:

1.生命周期

不少开发者会认为一个在Activity中建立的AsyncTask会随着Activity的销毁而销毁。然而事实并不是如此。AsynTask会一直执行,直到doInBackground()方法执行完毕,而后,若是cancel(boolean)被调用,那么onCancelled(Result result)方法会被执行;不然,执行onPostExecute(Result result)方法。若是咱们的Activity销毁以前,没有取消AsyncTask,这有可能让咱们的应用崩溃(crash)。由于它想要处理的view已经不存在了。因此,咱们是必须确保在销毁活动以前取消任务。总之,咱们使用AsyncTask须要确保AsyncTask正确的取消。

2.内存泄漏

若是AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会保留一个对Activity的引用。若是Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,致使Activity没法被回收,引发内存泄漏。

3.结果丢失

屏幕旋转或Activity在后台被系统杀掉等状况会致使Activity的从新建立,以前运行的AsyncTask会持有一个以前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将再也不生效。

4.并行仍是串行

在Android1.6以前的版本,AsyncTask是串行的,在1.6以后的版本,采用线程池处理并行任务,可是从Android 3.0开始,为了不AsyncTask所带来的并发错误,又采用一个线程来串行执行任务。能够使用executeOnExecutor()方法来并行地执行任务。

AsyncTask原理
  • AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中线程池SerialExecutor用于任务的排队,而线程池THREAD_POOL_EXECUTOR用于真正地执行任务,InternalHandler用于将执行环境从线程池切换到主线程。
  • sHandler是一个静态的Handler对象,为了可以将执行环境切换到主线程,这就要求sHandler这个对象必须在主线程建立。因为静态成员会在加载类的时候进行初始化,所以这就变相要求AsyncTask的类必须在主线程中加载,不然同一个进程中的AsyncTask都将没法正常工做。

五、onSaveInstanceState() 与 onRestoreIntanceState()

Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并非生命周期方法,它们不一样于 onCreate()、onPause()等生命周期方法,它们并不必定会被触发。当应用遇到意外状况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState() 会被调用。可是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。由于在这种状况下,用户的行为决定了不须要保存Activity的状态。一般onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。 在activity被杀掉以前调用保存每一个实例的状态,以保证该状态能够在onCreate(Bundle)或者onRestoreInstanceState(Bundle) (传入的Bundle参数是由onSaveInstanceState封装好的)中恢复。这个方法在一个activity被杀死前调用,当该activity在未来某个时刻回来时能够恢复其先前状态。 例如,若是activity B启用后位于activity A的前端,在某个时刻activity A由于系统回收资源的问题要被杀掉,A经过onSaveInstanceState将有机会保存其用户界面状态,使得未来用户返回到activity A时能经过onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢复界面的状态

深刻理解

六、android中进程的优先级?

1. 前台进程:

即与用户正在交互的Activity或者Activity用到的Service等,若是系统内存不足时前台进程是最晚被杀死的

2. 可见进程:

能够是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但因为失了焦点而不能与用户交互

3. 服务进程:

其中运行着使用startService方法启动的Service,虽然不被用户可见,可是倒是用户关心的,例如用户正在非音乐界面听的音乐或者正在非下载页面下载的文件等;当系统要空间运行,前二者进程才会被终止

4. 后台进程:

其中运行着执行onStop方法而中止的程序,可是却不是用户当前关心的,例如后台挂着的QQ,这时的进程系统一旦没了有内存就首先被杀死

5. 空进程:

不包含任何应用程序的进程,这样的进程系统是通常不会让他存在的

七、Bunder传递对象为何须要序列化?Serialzable和Parcelable的区别?

由于bundle传递数据时只支持基本数据类型,因此在传递对象时须要序列化转换成可存储或可传输的本质状态(字节流)。序列化后的对象能够在网络、IPC(好比启动另外一个进程的Activity、Service和Reciver)之间进行传输,也能够存储到本地。

Serializable(Java自带):

Serializable 是序列化的意思,表示将一个对象转换成存储或可传输的状态。序列化后的对象能够在网络上进传输,也能够存储到本地。

Parcelable(android专用):

除了Serializable以外,使用Parcelable也能够实现相同的效果,不过不一样于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这也就实现传递对象的功能了。

区别总结以下图所示:

image

八、动画

  • tween 补间动画。经过指定View的初末状态和变化方式,对View的内容完成一系列的图形变换来实现动画效果。 Alpha, Scale ,Translate, Rotate。
  • frame 帧动画。AnimationDrawable控制animation-list.xml布局
  • PropertyAnimation 属性动画3.0引入,属性动画核心思想是对值的变化。

Property Animation 动画有两个步聚:

1.计算属性值

2.为目标对象的属性设置属性值,即应用和刷新动画

image

计算属性分为3个过程:

过程一:

计算已完成动画分数 elapsed fraction。为了执行一个动画,你须要建立一个ValueAnimator,而且指定目标对象属性的开始、结束和持续时间。在调用 start 后的整个动画过程当中,ValueAnimator 会根据已经完成的动画时间计算获得一个0 到 1 之间的分数,表明该动画的已完成动画百分比。0表示 0%,1 表示 100%。

过程二:

计算插值(动画变化率)interpolated fraction 。当 ValueAnimator计算完已完成的动画分数后,它会调用当前设置的TimeInterpolator,去计算获得一个interpolated(插值)分数,在计算过程当中,已完成动画百分比会被加入到新的插值计算中。

过程三:

计算属性值当插值分数计算完成后,ValueAnimator会根据插值分数调用合适的 TypeEvaluator去计算运动中的属性值。 以上分析引入了两个概念:已完成动画分数(elapsed fraction)、插值分数( interpolated fraction )。

原理及特色:

1.属性动画:

插值器:做用是根据时间流逝的百分比来计算属性变化的百分比

估值器:在1的基础上由这个东西来计算出属性到底变化了多少数值的类

其实就是利用插值器和估值器,来计出各个时刻View的属性,而后经过改变View的属性来实现View的动画效果。

2.View动画:

只是影像变化,view的实际位置还在原来地方。

3.帧动画:

是在xml中定义好一系列图片以后,使用AnimatonDrawable来播放的动画。

它们的区别:

属性动画才是真正的实现了 view 的移动,补间动画对view 的移动更像是在不一样地方绘制了一个影子,实际对象仍是处于原来的地方。 当动画的 repeatCount 设置为无限循环时,若是在Activity退出时没有及时将动画中止,属性动画会致使Activity没法释放而致使内存泄漏,而补间动画却没问题。 xml 文件实现的补间动画,复用率极高。在 Activity切换,窗口弹出时等情景中有着很好的效果。 使用帧动画时须要注意,不要使用过多特别大的图,容致使内存不足。

为何属性动画移动后仍可点击?

播放补间动画的时候,咱们所看到的变化,都只是临时的。而属性动画呢,它所改变的东西,却会更新到这个View所对应的矩阵中,因此当ViewGroup分派事件的时候,会正确的将当前触摸坐标,转换成矩阵变化后的坐标,这就是为何播放补间动画不会改变触摸区域的缘由了。

九、Context相关

  • 一、Activity和Service以及Application的Context是不同的,Activity继承自ContextThemeWraper.其余的继承自ContextWrapper。

  • 二、每个Activity和Service以及Application的Context是一个新的ContextImpl对象。

  • 三、getApplication()用来获取Application实例的,可是这个方法只有在Activity和Service中才能调用的到。那也许在绝大多数状况下咱们都是在Activity或者Servic中使用Application的,可是若是在一些其它的场景,好比BroadcastReceiver中也想得到Application的实例,这时就能够借助getApplicationContext()方法,getApplicationContext()比getApplication()方法的做用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法均可以拿到咱们的Application对象。

  • 四、建立对话框时不能够用Application的context,只能用Activity的context。

  • 五、Context的数量等于Activity的个数 + Service的个数 +1,这个1为Application。

十、Android各版本新特性

Android5.0新特性
  • MaterialDesign设计风格

  • 支持64位ART虚拟机(5.0推出的ART虚拟机,在5.0以前都是Dalvik。他们的区别是: Dalvik,每次运行,字节码都须要经过即时编译器转换成机器码(JIT)。 ART,第一次安装应用的时候,字节码就会预先编译成机器码(AOT))

  • 通知详情能够用户本身设计

Android6.0新特性
  • 动态权限管理

  • 支持快速充电的切换

  • 支持文件夹拖拽应用

  • 相机新增专业模式

Android7.0新特性
  • 多窗口支持

  • V2签名

  • 加强的Java8语言模式

  • 夜间模式

Android8.0(O)新特性
  • 优化通知

    通知渠道 (Notification Channel) 通知标志 休眠 通知超时 通知设置 通知清除

  • 画中画模式:清单中Activity设置android:supportsPictureInPicture

  • 后台限制

  • 自动填充框架

  • 系统优化

  • 等等优化不少

Android9.0(P)新特性
  • 室内WIFI定位

  • “刘海”屏幕支持

  • 安全加强

  • 等等优化不少

Android10.0(Q)目前曝光的新特性
  • 夜间模式:包括手机上的全部应用均可觉得其设置暗黑模式。
  • 桌面模式:提供相似于PC的体验,可是远远不能代替PC。
  • 屏幕录制:经过长按“电源”菜单中的"屏幕快照"来开启。

十一、Json

JSON的全称是JavaScript Object Notation,也就是JavaScript 对象表示法 JSON是存储和交换文本信息的语法,相似XML,可是比XML更小、更快,更易解析 JSON是轻量级的文本数据交换格式,独立于语言,具备可描述性,更易理解,对象能够包含多个名称/值对,好比:

{"name":"zhangsan" , "age":25}
复制代码

使用谷歌的GSON包进行解析,在 Android Studio 里引入依赖:

compile 'com.google.code.gson:gson:2.7'
复制代码

值得注意的是实体类中变量名称必须和json中的值名字相同。

使用示例:

一、解析成实体类:

Gson gson = new Gson();
Student student = gson.fromJson(json1, Student.class);
复制代码

二、解析成int数组:

Gson gson = new Gson();
int[] ages = gson.fromJson(json2, int[].class);
复制代码

三、直接解析成List.

Gson gson = new Gson();
List<Integer> ages = gson.fromJson(json2,  newTypeToken<List<Integer>>(){}.getType);

Gson gson = new Gson();
List<Student> students = gson.fromJson(json3, newTypeToke<List<Student>>(){}.getType);
复制代码
优势:
  • 轻量级的数据交换格式
  • 读写更加容易
  • 易于机器的解析和生成
缺点:
  • 语义性较差,不如 xml 直观

十二、android中有哪几种解析xml的类,官方推荐哪一种?以及它们的原理和区别?

DOM解析

优势:

1.XML树在内存中完整存储,所以能够直接修改其数据结构.

2.能够经过该解析器随时访问XML树中的任何一个节点.

3.DOM解析器的API在使用上也相对比较简单.

缺点:

若是XML文档体积比较大时,将文档读入内存是非消耗系统资源的.

使用场景:

  • DOM 是与平台和语言无关的方式表示 XML文档的官方 W3C 标准.
  • DOM 是以层次结构组织的节点的集合.这个层次结构容许开人员在树中寻找特定信息.分析该结构一般须要加载整个文档和构造层次结构,而后才能进行任何工做.
  • DOM 是基于对象层次结构的.
SAX解析

优势:

SAX 对内存的要求比较低,由于它让开发人员本身来决定所要处理的标签.特别是当开发人员只须要处理文档中包含的部分数据时,SAX 这种扩展能力获得了更好的体现.

缺点:

用SAX方式进行XML解析时,须要顺序执行,因此很难访问同一文档中的不一样数据.此外,在基于该方式的解析编码程序也相对复杂.

使用场景:

对于含有数据量十分巨大,而又不用对文档的全部数据行遍历或者分析的时候,使用该方法十分有效.该方法不将整个文档读入内存,而只需读取到程序所需的文档标记处便可.

Xmlpull解析

android SDK提供了xmlpullapi,xmlpull和sax相似,是基于流(stream)操做文件,后者根据节点事件回调开发者编写的处理程序.由于是基于流的处理,所以xmlpull和sax都比较节约内存资源,不会像dom那样要把全部节点以对象树的形式展示在内存中.xmpull比sax更简明,并且不须要扫描完整个流.

1三、Jar和Aar的区别

Jar包里面只有代码,aar里面不光有代码还包括资源文件,好比 drawable 文件,xml资源文件。对于一些不常变更的 Android Library,咱们能够直接引用 aar,加快编译速度。

1四、Android为每一个应用程序分配的内存大小是多少

android程序内存通常限制在16M,也有的是24M。近几年手机发展较快,通常都会分配两百兆左右,和具体机型有关。

1五、更新UI方式

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable),View.postDelay(Runnable, long)(能够理解为在当前操做视图UI线程添加队列)
  • Handler
  • AsyncTask
  • Rxjava
  • LiveData

1六、ContentProvider使用方法。

进行跨进程通讯,实现进程间的数据交互和共享。经过Context 中 getContentResolver() 得到实例,经过 Uri匹配进行数据的增删改查。ContentProvider使用表的形式来组织数据,不管数据的来源是什么,ConentProvider 都会认为是一种表,而后把数据组织成表格。

1七、Thread、AsyncTask、IntentService的使用场景与特色。

  1. Thread线程,独立运行与于 Activity 的,当Activity 被 finish 后,若是没有主动中止 Thread或者 run 方法没有执行完,其会一直执行下去。

  2. AsyncTask 封装了两个线程池和一个Handler(SerialExecutor用于排队,THREAD_POOL_EXECUTOR为真正的执行任务,Handler将工做线程切换到主线程),其必须在 UI线程中建立,execute 方法必须在 UI线程中执行,一个任务实例只容许执行一次,执行屡次抛出异常,用于网络请求或者简单数据处理。

  3. IntentService:处理异步请求,实现多线程,在onHandleIntent中处理耗时操做,多个耗时任务会依次执行,执行完毕自动结束。

1八、Merge、ViewStub 的做用。

Merge: 减小视图层级,能够删除多余的层级。

ViewStub: 按需加载,减小内存使用量、加快渲染速度、不支持 merge 标签。

1九、activity的startActivity和context的startActivity区别?

(1)、从Activity中启动新的Activity时能够直接mContext.startActivity(intent)就好

(2)、若是从其余Context中启动Activity则必须给intent设置Flag:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ; 
mContext.startActivity(intent);
复制代码
20、怎么在Service中建立Dialog对话框?

1.在咱们取得Dialog对象后,需给它设置类型,即:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
复制代码

2.在Manifest中加上权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINOW" />
复制代码

2一、Asset目录与res目录的区别?

assets:不会在 R 文件中生成相应标记,存放到这里的资源在打包时会打包到程序安装包中。(经过 AssetManager 类访问这些文件)

res:会在 R 文件中生成 id 标记,资源在打包时若是使用到则打包到安装包中,未用到不会打入安装包中。

res/anim:存放动画资源。

res/raw:和 asset 下文件同样,打包时直接打入程序安装包中(会映射到 R 文件中)。

2二、Android怎么加速启动Activity?

  • onCreate() 中不执行耗时操做 把页面显示的 View 细分一下,放在 AsyncTask 里逐步显示,用 Handler 更好。这样用户的看到的就是有层次有步骤的一个个的 View 的展现,不会是先看到一个黑屏,而后一下显示全部 View。最好作成动画,效果更天然。
  • 利用多线程的目的就是尽量的减小 onCreate() 和 onReume() 的时间,使得用户能尽快看到页面,操做页面。
  • 减小主线程阻塞时间。
  • 提升 Adapter 和 AdapterView 的效率。
  • 优化布局文件。

2三、Handler机制

Android消息循环流程图以下所示:

image

主要涉及的角色以下所示:

  • message:消息。
  • MessageQueue:消息队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message。读取会自动删除消息,单链表维护,插入和删除上有优点。在其next()方法中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
  • Looper:消息循环器,负责关联线程以及消息的分发,在该线程下从 MessageQueue获取 Message,分发给Handler,Looper建立的时候会建立一个 MessageQueue,调用loop()方法的时候消息循环开始,其中会不断调用messageQueue的next()方法,当有消息就处理,不然阻塞在messageQueue的next()方法中。当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,而后loop()方法也就跟着退出。
  • Handler:消息处理器,负责发送并处理消息,面向开发者,提供 API,并隐藏背后实现的细节。

整个消息的循环流程仍是比较清晰的,具体说来:

  • 一、Handler经过sendMessage()发送消息Message到消息队列MessageQueue。
  • 二、Looper经过loop()不断提取触发条件的Message,并将Message交给对应的target handler来处理。
  • 三、target handler调用自身的handleMessage()方法来处理Message。

事实上,在整个消息循环的流程中,并不仅有Java层参与,不少重要的工做都是在C++层来完成的。咱们来看下这些类的调用关系。

image

注:虚线表示关联关系,实线表示调用关系。

在这些类中MessageQueue是Java层与C++层维系的桥梁,MessageQueue与Looper相关功能都经过MessageQueue的Native方法来完成,而其余虚线链接的类只有关联关系,并无直接调用的关系,它们发生关联的桥梁是MessageQueue。

总结
  • Handler 发送的消息由 MessageQueue 存储管理,并由 Looper 负责回调消息到 handleMessage()。
  • 线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用者所在线程决定。
Handler 引发的内存泄露缘由以及最佳解决方案

Handler 容许咱们发送延时消息,若是在延时期间用户关闭了 Activity,那么该 Activity 会泄露。 这个泄露是由于 Message 会持有 Handler,而又由于 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就致使 Activity 泄露。

解决:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并在Acitivity的onDestroy()中调用handler.removeCallbacksAndMessages(null)及时移除全部消息。

为何咱们能在主线程直接使用 Handler,而不须要建立 Looper ?

一般咱们认为 ActivityThread 就是主线程。事实上它并非一个线程,而是主线程操做的管理者。在 ActivityThread.main() 方法中调用了 Looper.prepareMainLooper() 方法建立了 主线程的 Looper ,而且调用了 loop() 方法,因此咱们就能够直接使用 Handler 了。

所以咱们能够利用 Callback 这个拦截机制来拦截 Handler 的消息。如大部分插件化框架中Hook ActivityThread.mH 的处理。

主线程的 Looper 不容许退出

主线程不容许退出,退出就意味 APP 要挂。

Handler 里藏着的 Callback 能干什么?

Handler.Callback 有优先处理消息的权利 ,当一条消息被 Callback 处理并拦截(返回 true),那么 Handler 的 handleMessage(msg) 方法就不会被调用了;若是 Callback 处理了消息,可是并无拦截,那么就意味着一个消息能够同时被 Callback 以及 Handler 处理。

建立 Message 实例的最佳方式

为了节省开销,Android 给 Message 设计了回收机制,因此咱们在使用的时候尽可能复用 Message ,减小内存消耗:

  • 经过 Message 的静态方法 Message.obtain();
  • 经过 Handler 的公有方法 handler.obtainMessage()。
子线程里弹 Toast 的正确姿式

本质上是由于 Toast 的实现依赖于 Handler,按子线程使用 Handler 的要求修改便可,同理的还有 Dialog。

妙用 Looper 机制
  • 将 Runnable post 到主线程执行;
  • 利用 Looper 判断当前线程是不是主线程。
主线程的死循环一直运行是否是特别消耗CPU资源呢?

并非,这里就涉及到Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,经过往pipe管道写端写入数据来唤醒主线程工做。这里采用的epoll机制,是一种IO多路复用机制,能够同时监控多个描述符,当某个描述符就绪(读或写就绪),则马上通知相应程序进行读或写操做,本质是同步I/O,即读写是阻塞的。因此说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。

handler postDelay这个延迟是怎么实现的?

handler.postDelay并非先等待必定的时间再放入到MessageQueue中,而是直接进入MessageQueue,以MessageQueue的时间顺序排列和唤醒的方式结合实现的。

如何保证在msg.postDelay状况下保证消息次序?

Handler 都没搞懂,拿什么去跳槽啊?

2四、程序A可否接收到程序B的广播?

能,使用全局的BroadCastRecevier能进行跨进程通讯,可是注意它只能被动接收广播。此外,LocalBroadCastRecevier只限于本进程的广播间通讯。

2五、数据加载更多涉及到分页,你是怎么实现的?

分页加载就是一页一页加载数据,当滑动到底部、没有更多数据加载的时候,咱们能够手动调用接口,从新刷新RecyclerView。

2六、经过google提供的Gson解析json时,定义JavaBean的规则是什么?

1). 实现序列化 Serializable

2). 属性私有化,并提供get,set方法

3). 提供无参构造

4). 属性名必须与json串中属性名保持一致 (由于Gson解析json串底层用到了Java的反射原理)

2七、json解析方式的两种区别?

1,SDK提供JSONArray,JSONObject

2,google提供的 Gson 经过fromJson()实现对象的反序列化(即将json串转换为对象类型) 经过toJson()实现对象的序列化 (即将对象类型转换为json串)

2八、线程池的相关知识。

Android中的线程池都是直接或间接经过配置ThreadPoolExecutor来实现不一样特性的线程池.Android中最多见的类具备不一样特性的线程池分别为FixThreadPool、CachedhreadPool、SingleThreadPool、ScheduleThreadExecutr.

1).FixThreadPool

只有核心线程,而且数量固定的,也不会被回收,全部线程都活动时,由于队列没有限制大小,新任务会等待执行.

优势:更快的响应外界请求.

2).SingleThreadPool

只有一个核心线程,确保全部的任务都在同一线程中按序完成.所以不须要处理线程同步的问题.

3).CachedThreadPool

只有非核心线程,最大线程数很是大,全部线程都活动时会为新任务建立新线程,不然会利用空闲线程(60s空闲时间,过了就会被回收,因此线程池中有0个线程的可能)处理任务.

优势:任何任务都会被当即执行(任务队列SynchronousQuue至关于一个空集合);比较适合执行大量的耗时较少的任务.

4).ScheduledThreadPool

核心线程数固定,非核心线程(闲着没活干会被当即回收数)没有限制.

优势:执行定时任务以及有固定周期的重复任务

2九、内存泄露,怎样查找,怎么产生的内存泄露?

1.资源对象没关闭形成的内存泄漏

描述: 资源性对象好比(Cursor,File文件等)每每都用了一些缓冲,咱们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不只存在于 java虚拟机内,还存在于java虚拟机外。若是咱们仅仅是把它的引用设置为null,而不关闭它们,每每会形成内存泄漏。由于有些资源性对象,好比SQLiteCursor(在析构函数finalize(),若是咱们没有关闭它,它本身会调close()关闭),若是咱们没有关闭它,系统在回收它时也会关闭它,可是这样的效率过低了。所以对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,而后才置为null.在咱们的程序退出时必定要确保咱们的资源性对象已经关闭。

程序中常常会进行查询数据库的操做,可是常常会有使用完毕Cursor后没有关闭的状况。若是咱们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操做的状况下才会复现内存问题,这样就会给之后的测试和问题排查带来困难和风险。

2.构造Adapter时,没有使用缓存的convertView

描述: 以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 来向ListView提供每个item所须要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化必定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,而后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此能够看出,若是咱们不去使用 convertView,而是每次都在getView()中从新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用愈来愈大。 ListView回收list item的view对象的过程能够查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代码:

public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...); 
... ... 
return view; 
}
复制代码

修正示例代码:

public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = null; 
if (convertView != null) { 
view = convertView; 
populate(view, getItem(position)); 
... 
} else { 
view = new Xxx(...); 
... 
} 
return view; 
}
复制代码

3.Bitmap对象不在使用时调用recycle()释放内存

描述: 有时咱们会手工的操做Bitmap对象,若是一个Bitmap对象比较占内存,当它不在被使用的时候,能够调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视状况而定。能够看一下代码中的注释:

/* •Free up the memory associated with thisbitmap's pixels, and mark the •bitmap as "dead", meaning itwill throw an exception if getPixels() or •setPixels() is called, and will drawnothing. This operation cannot be •reversed, so it should only be called ifyou are sure there are no •further uses for the bitmap. This is anadvanced call, and normally need •not be called, since the normal GCprocess will free up this memory when •there are no more references to thisbitmap. /

4.试着使用关于application的context来替代和activity相关的context

这是一个很隐晦的内存泄漏的状况。有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他本身的范围以外。使用Application context。这个context的生存周期和你的应用的生存周期同样长,而不是取决于activity的生存周期。若是你想保持一个长期生存的对象,而且这个对象须要一个context,记得使用application对象。你能够经过调用 Context.getApplicationContext() or Activity.getApplication()来得到。更多的请看这篇文章如何避免 Android内存泄漏。

5.注册没取消形成的内存泄漏

一些Android程序可能引用咱们的Anroid程序的对象(好比注册机制)。即便咱们的Android程序已经结束了,可是别的引用程序仍然还有对咱们的Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。调用registerReceiver后未调用unregisterReceiver。 好比:假设咱们但愿在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则能够在LockScreen中定义一个 PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当须要显示锁屏界面的时候就会建立一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。 可是若是在释放 LockScreen对象的时候忘记取消咱们以前注册的PhoneStateListener对象,则会致使LockScreen没法被垃圾回收。若是不断的使锁屏界面显示和消失,则最终会因为大量的LockScreen对象没有办法被回收而引发OutOfMemory,使得system_process 进程挂掉。 虽然有些系统程序,它自己好像是能够自动取消注册的(固然不及时),可是咱们仍是应该在咱们的程序中明确的取消注册,程序结束时应该把全部的注册都取消掉。

6.集合中对象没清理形成的内存泄漏

咱们一般把一些对象的引用加入到了集合中,当咱们不须要该对象时,并无把它的引用从集合中清理掉,这样这个集合就会愈来愈大。若是这个集合是static的话,那状况就更严重了。

查找内存泄漏能够使用Android Studio 自带的AndroidProfiler工具或MAT,也能够使用Square产品的LeakCanary.

一、使用AndroidProfiler的MEMORY工具:

运行程序,对每个页面进行内存分析检查。首先,反复打开关闭页面5次,而后收到GC(点击Profile MEMORY左上角的垃圾桶图标),若是此时total内存尚未恢复到以前的数值,则可能发生了内存泄露。此时,再点击Profile MEMORY左上角的垃圾桶图标旁的heap dump按钮查看当前的内存堆栈状况,选择按包名查找,找到当前测试的Activity,若是引用了多个实例,则代表发生了内存泄露。

二、使用MAT:

一、运行程序,全部功能跑一遍,确保没有改出问题,彻底退出程序,手动触发GC,而后使用adb shell dumpsys meminfo packagename -d命令查看退出界面后Objects下的Views和Activities数目是否为0,若是不是则经过Leakcanary检查可能存在内存泄露的地方,最后经过MAT分析,如此反复,改善满意为止。

一、在使用MAT以前,先使用as的Profile中的Memory去获取要分析的堆内存快照文件.hprof,若是要测试某个页面是否产生内存泄漏,能够先dump出没进入该页面的内存快照文件.hprof,而后,一般执行5次进入/退出该页面,而后再dump出此刻的内存快照文件.hprof,最后,将二者比较,若是内存相除明显,则可能发生内存泄露。(注意:MAT须要标准的.hprof文件,所以在as的Profiler中GC后dump出的内存快照文件.hprof必须手动使用android sdk platform-tools下的hprof-conv程序进行转换才能被MAT打开)

二、而后,使用MAT打开前面保存的2份.hprof文件,打开Overview界面,在Overview界面下面有4中action,其中最经常使用的就是Histogram和Dominator Tree。

Dominator Tree:支配树,按对象大小降序列出对象和其所引用的对象,注重引用关系分析。选择Group by package,找到当前要检测的类(或者使用顶部的Regex直接搜索),查看它的Object数目是否正确,若是多了,则判断发生了内存泄露。而后,右击该类,选择Merge Shortest Paths to GC Root中的exclude all phantom/weak/soft etc.references选项来查看该类的GC强引用链。最后,经过引用链便可看到最终强引用该类的对象。

Histogram:直方图注重量的分析。使用方式与Dominator Tree相似。

三、对比hprof文件,检测出复杂状况下的内存泄露:

通用对比方式:在Navigation History下面选择想要对比的dominator_tree/histogram,右击选择Add to Compare Basket,而后在Compare Basket一栏中点击红色感叹号(Compare the results)生成对比表格(Compared Tables),在顶部Regex输入要检测的类,查看引用关系或对象数量去进行分析便可。

针对于Historam的快速对比方式:直接选择Histogram上方的Compare to another Heap Dump选择要比较的hprof文件的Historam便可。

30、类的初始化顺序依次是?

(静态变量、静态代码块)>(变量、代码块)>构造方法

3一、JSON的结构?

json是一种轻量级的数据交换格式, json简单说就是对象和数组,因此这两种结构就是对象和数组两种结构,经过这两种结构能够表示各类复杂的结构

一、对象:对象表示为“{}”扩起来的内容,数据结构为 {key:value,key:value,...}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,因此很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型能够是 数字、字符串、数组、对象几种。

二、数组:数组在json中是中括号“[]”扩起来的内容,数据结构为 ["java","javascript","vb",...],取值方式和全部语言中同样,使用索引获取,字段值的类型能够是 数字、字符串、数组、对象几种。 通过对象、数组2种结构就能够组合成复杂的数据结构了。

3二、ViewPager使用细节,如何设置成每次只初始化当前的Fragment,其余的不初始化(提示:Fragment懒加载)?

自定义一个 LazyLoadFragment 基类,利用 setUserVisibleHint 和 生命周期方法,经过对 Fragment 状态判断,进行数据加载,并将数据加载的接口提供开放出去,供子类使用。而后在子类 Fragment 中实现 requestData 方法便可。这里添加了一个 isDataLoaded 变量,目的是避免重复加载数据。考虑到有时候须要刷新数据的问题,便提供了一个用于强制刷新的参数判断。

public abstract class LazyLoadFragment extends BaseFragment {
    protected boolean isViewInitiated;
    protected boolean isDataLoaded;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        isViewInitiated = true;
        prepareRequestData();
    }
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        prepareRequestData();
    }
    public abstract void requestData();
    public boolean prepareRequestData() {
        return prepareRequestData(false);
    }
    public boolean prepareRequestData(boolean forceUpdate) {
        if (getUserVisibleHint() && isViewInitiated && (!isDataLoaded || forceUpdate)) {
            requestData();
            isDataLoaded = true;
            return true;
        }
        return false;
    }
}
复制代码

3五、Android为何引入Parcelable?

能够确定的是,二者都是支持序列化和反序列化的操做。

二者最大的区别在于 存储媒介的不一样,Serializable 使用 I/O 读写存储在硬盘上,而 Parcelable 是直接 在内存中读写。很明显,内存的读写速度一般大于 IO 读写,因此在 Android 中传递数据优先选择 Parcelable。

Serializable 会使用反射,序列化和反序列化过程须要大量 I/O 操做, Parcelable 自已实现封送和解封(marshalled &unmarshalled)操做不须要用反射,数据也存放在 Native 内存中,效率要快不少。

3六、有没有尝试简化Parcelable的使用?

使用Parcelable插件(Android Parcelable code generator)进行实体类的序列化的实现。

3七、Bitmap 使用时候注意什么?

一、要选择合适的图片规格(bitmap类型):

ALPHA_8   每一个像素占用1byte内存        
ARGB_4444 每一个像素占用2byte内存       
ARGB_8888 每一个像素占用4byte内存(默认)      
RGB_565 每一个像素占用2byte内存
复制代码

二、下降采样率。BitmapFactory.Options 参数inSampleSize的使用,先把options.inJustDecodeBounds设为true,只是去读取图片的大小,在拿到图片的大小以后和要显示的大小作比较经过calculateInSampleSize()函数计算inSampleSize的具体值,获得值以后。options.inJustDecodeBounds设为false读图片资源。

三、复用内存。即,经过软引用(内存不够的时候才会回收掉),复用内存块,不须要再从新给这个bitmap申请一块新的内存,避免了一次内存的分配和回收,从而改善了运行效率。

四、使用recycle()方法及时回收内存。

五、压缩图片。

3八、Oom 是否能够try catch ?

只有在一种状况下,这样作是可行的:

在try语句中声明了很大的对象,致使OOM,而且能够确认OOM是由try语句中的对象声明致使的,那么在catch语句中,能够释放掉这些对象,解决OOM的问题,继续执行剩余语句。

可是这一般不是合适的作法。

Java中管理内存除了显式地catch OOM以外还有更多有效的方法:好比SoftReference, WeakReference, 硬盘缓存等。 在JVM用光内存以前,会屡次触发GC,这些GC会下降程序运行的效率。 若是OOM的缘由不是try语句中的对象(好比内存泄漏),那么在catch语句中会继续抛出OOM。

3九、多进程场景碰见过么?

一、在新的进程中,启动前台Service,播放音乐。 二、一个成熟的应用必定是多模块化的。首先多进程开发能为应用解决了OOM问题,由于Android对内存的限制是针对于进程的,因此,当咱们须要加载大图之类的操做,能够在新的进程中去执行,避免主进程OOM。并且假如图片浏览进程打开了一个过大的图片,java heap 申请内存失败,该进程崩溃并不影响我主进程的使用。

40、Canvas.save()跟Canvas.restore()的调用时机

save:用来保存Canvas的状态。save以后,能够调用Canvas的平移、放缩、旋转、错切、裁剪等操做。

restore:用来恢复Canvas以前保存的状态。防止save后对Canvas执行的操做对后续的绘制有影响。

save和restore要配对使用(restore能够比save少,但不能多),若是restore调用次数比save多,会引起Error。save和restore操做执行的时机不一样,就能形成绘制的图形不一样。

4一、数据库升级增长表和删除表都不涉及数据迁移,可是修改表涉及到对原有数据进行迁移。升级的方法以下所示:

将现有表命名为临时表。 建立新表。 将临时表的数据导入新表。 删除临时表。

若是是跨版本数据库升级,能够有两种方式,以下所示:

逐级升级,肯定相邻版本与如今版本的差异,V1升级到V2,V2升级到V3,依次类推。 跨级升级,肯定每一个版本与如今数据库的差异,为每一个case编写专门升级大代码。

public class DBservice extends SQLiteOpenHelper{
    private String CREATE_BOOK = "create table book(bookId integer primarykey,bookName text);";
    private String CREATE_TEMP_BOOK = "alter table book rename to _temp_book";
    private String INSERT_DATA = "insert into book select *,'' from _temp_book";
    private String DROP_BOOK = "drop table _temp_book";
    public DBservice(Context context, String name, CursorFactory factory,int version) {
    super(context, name, factory, version);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    switch (newVersion) {
        case 2:
            db.beginTransaction();

            db.execSQL(CREATE_TEMP_BOOK);
            db.execSQL(CREATE_BOOK);
            db.execSQL(INSERT_DATA);
            db.execSQL(DROP_BOOK);

            db.setTransactionSuccessful();
            db.endTransaction();

            break;
    }
}
复制代码

4二、编译期注解跟运行时注解

运行期注解(RunTime)利用反射去获取信息仍是比较损耗性能的,对应@Retention(RetentionPolicy.RUNTIME)。

编译期(Compile time)注解,以及处理编译期注解的手段APT和Javapoet,对应@Retention(RetentionPolicy.CLASS)。 其中apt+javaPoet目前也是应用比较普遍,在一些大的开源库,如EventBus3.0+,页面路由 ARout、Dagger、Retrofit等均有使用的身影,注解不只仅是经过反射一种方式来使用,也能够使用APT在编译期处理

4三、bitmap recycler 相关

在Android中,Bitmap的存储分为两部分,一部分是Bitmap的数据,一部分是Bitmap的引用。 在Android2.3时代,Bitmap的引用是放在堆中的,而Bitmap的数据部分是放在栈中的,须要用户调用recycle方法手动进行内存回收,而在Android2.3以后,整个Bitmap,包括数据和引用,都放在了堆中,这样,整个Bitmap的回收就所有交给GC了,这个recycle方法就不再须要使用了。

bitmap recycler引起的问题:当图像的旋转角度小余两个像素点之间的夹角时,图像即便旋转也没法显示,所以,系统彻底能够认为图像没有发生变化。这时系统就直接引用同一个对象来进行操做,避免内存浪费。

4四、强引用置为null,会不会被回收?

不会当即释放对象占用的内存。 若是对象的引用被置为null,只是断开了当前线程栈帧中对该对象的引用关系,而 垃圾收集器是运行在后台的线程,只有当用户线程运行到安全点(safe point)或者安全区域才会扫描对象引用关系,扫描到对象没有被引用则会标记对象,这时候仍然不会当即释放该对象内存,由于有些对象是可恢复的(在 finalize方法中恢复引用 )。只有肯定了对象没法恢复引用的时候才会清除对象内存。

4五、Bundle传递数据为何须要序列化?

序列化,表示将一个对象转换成可存储或可传输的状态。序列化的缘由基本三种状况:

1.永久性保存对象,保存对象的字节序列到本地文件中;

2.对象在网络中传递;

3.对象在IPC间传递。

4六、广播传输的数据是否有限制,是多少,为何要限制?

Intent在传递数据时是有大小限制的,大约限制在1MB以内,你用Intent传递数据,实际上走的是跨进程通讯(IPC),跨进程通讯须要把数据从内核copy到进程中,每个进程有一个接收内核数据的缓冲区,默认是1M;若是一次传递的数据超过限制,就会出现异常。

不一样厂商表现不同有多是厂商修改了此限制的大小,也可能一样的对象在不一样的机器上大小不同。

传递大数据,不该该用Intent;考虑使用ContentProvider或者直接匿名共享内存。简单状况下能够考虑分段传输。

4七、是否了解硬件加速?

硬件加速就是运用GPU优秀的运算能力来加快渲染的速度,而一般的基于软件的绘制渲染模式是彻底利用CPU来完成渲染。

1.硬件加速是从API 11引入,API 14以后才默认开启。对于标准的绘制操做和控件都是支持的,可是对于自定义View的时候或者一些特殊的绘制函数就须要考虑是否须要关闭硬件加速。

2.咱们面对不支持硬件加速的状况,就须要限制硬件加速,这个兼容性的问题是由于硬件加速是把View的绘制函数转化为使用OpenGL的函数来进完成实际的绘制的,那么必然会存在OpenGL中不支持原始回执函数的状况,对于这些绘制函数,就会失效。

3.硬件加速的消耗问题,由于是使用OpenGL,须要把系统中OpenGL加载到内存中,OpenGL API调用就会占用8MB,而实际上会占用更多内存,而且使用了硬件必然增长耗电量了。

4.硬件加速的优点还有display list的设计,使用这个咱们不须要每次重绘都执行大量的代码,基于软件的绘制模式会重绘脏区域内的全部控件,而display只会更新列表,而后绘制列表内的控件。

  1. CPU更擅长复杂逻辑控制,而GPU得益于大量ALU和并行结构设计,更擅长数学运算。

4八、ContentProvider的权限管理(读写分离,权限控制-精确到表级,URL控制)。

 对于ContentProvider暴露出来的数据,应该是存储在本身应用内存中的数据,对于一些存储在外部存储器上的数据,并不能限制访问权限,使用ContentProvider就没有意义了。对于ContentProvider而言,有不少权限控制,能够在AndroidManifest.xml文件中对节点的属性进行配置,通常使用以下一些属性设置:

  • android:grantUriPermssions:临时许可标志。
  • android:permission:Provider读写权限。
  • android:readPermission:Provider的读权限。
  • android:writePermission:Provider的写权限。
  • android:enabled:标记容许系统启动Provider。
  • android:exported:标记容许其余应用程序使用这个Provider。
  • android:multiProcess:标记容许系统启动Provider相同的进程中调用客户端。

4九、Fragment状态保存

Fragment状态保存入口:

一、Activity的状态保存, 在Activity的onSaveInstanceState()里, 调用了FragmentManger的saveAllState()方法, 其中会对mActive中各个Fragment的实例状态和View状态分别进行保存.

二、FragmentManager还提供了public方法: saveFragmentInstanceState(), 能够对单个Fragment进行状态保存, 这是提供给咱们用的。

三、FragmentManager的moveToState()方法中, 当状态回退到ACTIVITY_CREATED, 会调用saveFragmentViewState()方法, 保存View的状态.

50、直接在Activity中建立一个thread跟在service中建立一个thread之间的区别?

在Activity中被建立:该Thread的就是为这个Activity服务的,完成这个特定的Activity交代的任务,主动通知该Activity一些消息和事件,Activity销毁后,该Thread也没有存活的意义了。

在Service中被建立:这是保证最长生命周期的Thread的惟一方式,只要整个Service不退出,Thread就能够一直在后台执行,通常在Service的onCreate()中建立,在onDestroy()中销毁。因此,在Service中建立的Thread,适合长期执行一些独立于APP的后台任务,比较常见的就是:在Service中保持与服务器端的长链接。

5一、如何计算一个Bitmap占用内存的大小,怎么保证加载Bitmap不产生内存溢出?

Bitamp 占用内存大小 = 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存
复制代码

注:这里inDensity表示目标图片的dpi(放在哪一个资源文件夹下),inTargetDensity表示目标屏幕的dpi,因此你能够发现inDensity和inTargetDensity会对Bitmap的宽高进行拉伸,进而改变Bitmap占用内存的大小。

在Bitmap里有两个获取内存占用大小的方法。

getByteCount():API12 加入,表明存储 Bitmap 的像素须要的最少内存。 getAllocationByteCount():API19 加入,表明在内存中为 Bitmap 分配的内存大小,代替了 getByteCount() 方法。 在不复用 Bitmap 时,getByteCount() 和 getAllocationByteCount 返回的结果是同样的。在经过复用 Bitmap 来解码图片时,那么 getByteCount() 表示新解码图片占用内存的大 小,getAllocationByteCount() 表示被复用 Bitmap 真实占用的内存大小(即 mBuffer 的长度)。

为了保证在加载Bitmap的时候不产生内存溢出,能够使用BitmapFactory进行图片压缩,主要有如下几个参数:

BitmapFactory.Options.inPreferredConfig:将ARGB_8888改成RGB_565,改变编码方式,节约内存。 BitmapFactory.Options.inSampleSize:缩放比例,能够参考Luban那个库,根据图片宽高计算出合适的缩放比例。 BitmapFactory.Options.inPurgeable:让系统能够内存不足时回收内存。

5二、对于应用更新这块是如何作的?(灰度,强制更新,分区域更新)

一、经过接口获取线上版本号,versionCode 二、比较线上的versionCode 和本地的versionCode,弹出更新窗口 三、下载APK文件(文件下载) 四、安装APK

灰度: (1)找单一渠道投放特别版本。 (2)作升级平台的改造,容许针对部分用户推送升级通知甚至版本强制升级。 (3)开放单独的下载入口。 (4)是两个版本的代码都打到app包里,而后在app端植入测试框架,用来控制显示哪一个版本。测试框架负责与服务器端api通讯,由服务器端控制app上A/B版本的分布,能够实现指定的一组用户看到A版本,其它用户看到B版本。服务端会有相应的报表来显示A/B版本的数量和效果对比。最后能够由服务端的后台来控制,所有用户在线切换到A或者B版本~

不管哪一种方法都须要作好版本管理工做,分配特别的版本号以示区别。 固然,既然是作灰度,数据监控(常规数据、新特性数据、主要业务数据)仍是要作到位,该打的数据桩要打。 还有,灰度版最好有收回的能力,通常就是强制升级下一个正式版。

强制更新:通常的处理就是进入应用就弹窗通知用户有版本更新,弹窗能够没有取消按钮并不能取消。这样用户就只能选择更新或者关闭应用了,固然也能够添加取消按钮,可是若是用户选择取消则直接退出应用。

增量更新:bsdiff:二进制差分工具bsdiff是相应的补丁合成工具,根据两个不一样版本的二进制文件,生成补丁文件.patch文件。经过bspatch使旧的apk文件与不定文件合成新的apk。 注意经过apk文件的md5值进行区分版本。

5三、请解释安卓为啥要加签名机制。

一、发送者的身份认证 因为开发商可能经过使用相同的 Package Name 来混淆替换已经安装的程序,以此保证签名不一样的包不被替换。

二、保证信息传输的完整性 签名对于包中的每一个文件进行处理,以此确保包中内容不被替换。

三、防止交易中的抵赖发生, Market 对软件的要求。

5四、为何bindService能够跟Activity生命周期联动?

一、bindService 方法执行时,LoadedApk 会记录 ServiceConnection 信息。

二、Activity 执行 finish 方法时,会经过 LoadedApk 检查 Activity 是否存在未注销/解绑的 BroadcastReceiver 和 ServiceConnection,若是有,那么会通知 AMS 注销/解绑对应的 BroadcastReceiver 和 Service,并打印异常信息,告诉用户应该主动执行注销/解绑的操做。

5五、如何经过Gradle配置多渠道包?

用于生成不一样渠道的包

android {  
    productFlavors {
        xiaomi {}
        baidu {}
        wandoujia {}
        _360 {}        // 或“"360"{}”,数字需下划线开头或加上双引号
    }
}
复制代码

执行./gradlew assembleRelease ,将会打出全部渠道的release包;

执行./gradlew assembleWandoujia,将会打出豌豆荚渠道的release和debug版的包;

执行./gradlew assembleWandoujiaRelease将生成豌豆荚的release包。

所以,能够结合buildType和productFlavor生成不一样的Build Variants,即类型与渠道不一样的组合。

5六、activty和Fragmengt之间怎么通讯,Fragmengt和Fragmengt怎么通讯?

(一)Handler

(二)广播

(三)事件总线:EventBus、RxBus、Otto

(四)接口回调

(五)Bundle和setArguments(bundle)

5七、自定义view效率高于xml定义吗?说明理由。

自定义view效率高于xml定义:

一、少了解析xml。

2.、自定义View 减小了ViewGroup与View之间的测量,包括父量子,子量自身,子在父中位置摆放,当子view变化时,父的某些属性都会跟着变化。

5八、广播注册通常有几种,各有什么优缺点?

第一种是常驻型(静态注册):当应用程序关闭后若是有信息广播来,程序也会被系统调用,本身运行。

第二种不常驻(动态注册):广播会跟随程序的生命周期。

动态注册

优势: 在android的广播机制中,动态注册优先级高于静态注册优先级,所以在必要状况下,是须要动态注册广播接收者的。

缺点: 当用来注册的 Activity 关掉后,广播也就失效了。

静态注册

优势: 无需担心广播接收器是否被关闭,只要设备是开启状态,广播接收器就是打开着的。

5九、服务启动通常有几种,服务和activty之间怎么通讯,服务和服务之间怎么通讯

方式:

一、startService:

onCreate()--->onStartCommand() ---> onDestory()

若是服务已经开启,不会重复的执行onCreate(), 而是会调用onStartCommand()。一旦服务开启跟调用者(开启者)就没有任何关系了。 开启者退出了,开启者挂了,服务还在后台长期的运行。 开启者不能调用服务里面的方法。

二、bindService:

onCreate() --->onBind()--->onunbind()--->onDestory()

bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。 绑定者能够调用服务里面的方法。

通讯:

一、经过Binder对象。

二、经过broadcast(广播)。

60、ddms 和 traceView 的区别?

ddms 原意是:davik debug monitor service。简单的说 ddms 是一个程序执行查看器,在里面能够看见线程和堆栈等信息,traceView 是程序性能分析器。traceview 是 ddms 中的一部份内容。

Traceview 是 Android 平台特有的数据采集和分析工具,它主要用于分析 Android 中应用程序的 hotspot(瓶颈)。Traceview 自己只是一个数据分析工具,而数据的采集则须要使用 Android SDK 中的 Debug 类或者利用DDMS 工具。两者的用法以下:开发者在一些关键代码段开始前调用 Android SDK 中 Debug 类的 startMethodTracing 函数,并在关键代码段结束前调用 stopMethodTracing 函数。这两个函数运行过程当中将采集运行时间内该应用全部线程(注意,只能是 Java线程) 的函数执行状况, 并将采集数据保存到/mnt/sdcard/下的一个文件中。 开发者而后须要利用 SDK 中的 Traceview工具来分析这些数据。

6一、ListView卡顿缘由

Adapter的getView方法里面convertView没有使用setTag和getTag方式;

在getView方法里面ViewHolder初始化后的赋值或者是多个控件的显示状态和背景的显示没有优化好,抑或是里面含有复杂的计算和耗时操做;

在getView方法里面 inflate的row 嵌套太深(布局过于复杂)或者是布局里面有大图片或者背景所致;

Adapter多余或者不合理的notifySetDataChanged;

listview 被多层嵌套,屡次的onMessure致使卡顿,若是多层嵌套没法避免,建议把listview的高和宽设置为match_parent. 若是是代码继承的listview,那么也请你别忘记为你的继承类添加上LayoutPrams,注意高和宽都mactch_parent的;

6二、AndroidManifest的做用与理解

AndroidManifest.xml文件,也叫清单文件,来获知应用中是否包含该组件,若是有会直接启动该组件。能够理解是一个应用的配置文件。

做用:

  • 为应用的 Java 软件包命名。软件包名称充当应用的惟一标识符。
  • 描述应用的各个组件,包括构成应用的 Activity、服务、广播接收器和内容提供程序。它还为实现每一个组件的类命名并发布其功能,例如它们能够处理的 Intent - 消息。这些声明向 Android 系统告知有关组件以及能够启动这些组件的条件的信息。
  • 肯定托管应用组件的进程。
  • 声明应用必须具有哪些权限才能访问 API 中受保护的部分并与其余应用交互。还声明其余应用与该应用组件交互所需具有的权限
  • 列出 Instrumentation类,这些类可在应用运行时提供分析和其余信息。这些声明只会在应用处于开发阶段时出如今清单中,在应用发布以前将移除。
  • 声明应用所需的最低 Android API 级别
  • 列出应用必须连接到的库

6三、LaunchMode应用场景

standard,建立一个新的Activity。

singleTop,栈顶不是该类型的Activity,建立一个新的Activity。不然,onNewIntent。

singleTask,回退栈中没有该类型的Activity,建立Activity,不然,onNewIntent+ClearTop。

注意:

设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在;若是存在这样的Task,它就会在这个Task中启动,不然就会在新的任务栈中启动。所以, 若是咱们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。

若是设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 若是存在,就会把位于这个Activity实例上面的Activity所有结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。

在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面能够有其余的Activity。这点与singleInstance是有区别的。

singleInstance,回退栈中,只有这一个Activity,没有其余Activity。

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

例如,某个新闻客户端的新闻内容页面,若是收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。

singleTask适合做为程序入口点。

例如浏览器的主界面。无论从多少个应用启动浏览器,只会启动主界面一次,其他状况都会走onNewIntent,而且会清空主界面上面的其余页面。

singleInstance应用场景:

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

6四、说说Activity、Intent、Service 是什么关系

他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都是 Android 四大组件之一。他俩都是 Context 类的子类 ContextWrapper 的子类,所以他俩能够算是兄弟关系吧。不过兄弟俩各有各自的本领,Activity 负责用户界面的显示和交互,Service 负责后台任务的处理。Activity 和 Service 之间能够经过 Intent 传递数据,所以 能够把 Intent 看做是通讯使者。

6五、ApplicationContext和ActivityContext的区别

这是两种不一样的context,也是最多见的两种.第一种中context的生命周期与Application的生命周期相关的,context随着Application的销毁而销毁,伴随application的一辈子,与activity的生命周期无关.第二种中的context跟Activity的生命周期是相关的,可是对一个Application来讲,Activity能够销毁几回,那么属于Activity的context就会销毁屡次.至于用哪一种context,得看应用场景。还有就是,在使用context的时候,当心内存泄露,防止内存泄露,注意一下几个方面:

  • 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity自己生命周期是同样的。
  • 对于生命周期长的对象,能够使用application context。
  • 避免非静态的内部类,尽可能使用静态类,避免生命周期问题,注意内部类对外部对象引用致使的生命周期变化。

6六、Handler、Thread和HandlerThread的差异

一、Handler:在android中负责发送和处理消息,经过它能够实现其余支线线程与主线程之间的消息通信。

二、Thread:Java进程中执行运算的最小单位,亦即执行处理机调度的基本单位。某一进程中一路单独运行的程序。

三、HandlerThread:一个继承自Thread的类HandlerThread,Android中没有对Java中的Thread进行任何封装,而是提供了一个继承自Thread的类HandlerThread类,这个类对Java的Thread作了不少便利的封装。HandlerThread继承于Thread,因此它本质就是个Thread。与普通Thread的差异就在于,它在内部直接实现了Looper的实现,这是Handler消息机制必不可少的。有了本身的looper,可让咱们在本身的线程中分发和处理消息。若是不用HandlerThread的话,须要手动去调用Looper.prepare()和Looper.loop()这些方法。

6七、ThreadLocal的原理

ThreadLocal是一个关于建立线程局部变量的类。使用场景以下所示:

  • 实现单个线程单例以及单个线程上下文信息存储,好比交易id等。

  • 实现线程安全,非线程安全的对象使用ThreadLocal以后就会变得线程安全,由于每一个线程都会有一个对应的实例。 承载一些线程相关的数据,避免在方法中来回传递参数。

当须要使用多线程时,有个变量恰巧不须要共享,此时就没必要使用synchronized这么麻烦的关键字来锁住,每一个线程都至关于在堆内存中开辟一个空间,线程中带有对共享变量的缓冲区,经过缓冲区将堆内存中的共享变量进行读取和操做,ThreadLocal至关于线程内的内存,一个局部变量。每次能够对线程自身的数据读取和操做,并不须要经过缓冲区与 主内存中的变量进行交互。并不会像synchronized那样修改主内存的数据,再将主内存的数据复制到线程内的工做内存。ThreadLocal可让线程独占资源,存储于线程内部,避免线程堵塞形成CPU吞吐降低。

在每一个Thread中包含一个ThreadLocalMap,ThreadLocalMap的key是ThreadLocal的对象,value是独享数据。

6八、计算一个view的嵌套层级

private int getParents(ViewParents view){
    if(view.getParents() == null) 
        return 0;
    } else {
    return (1 + getParents(view.getParents));
   }
}
复制代码

6九、MVP,MVVM,MVC解释和实践

MVC:
  • 视图层(View) 对应于xml布局文件和java代码动态view部分
  • 控制层(Controller) MVC中Android的控制层是由Activity来承担的,Activity原本主要是做为初始化页面,展现数据的操做,可是由于XML视图功能太弱,因此Activity既要负责视图的显示又要加入控制逻辑,承担的功能过多。
  • 模型层(Model) 针对业务模型,创建数据结构和相关的类,它主要负责网络请求,数据库处理,I/O的操做。
总结

具备必定的分层,model完全解耦,controller和view并无解耦 层与层之间的交互尽可能使用回调或者去使用消息机制去完成,尽可能避免直接持有 controller和view在android中没法作到完全分离,但在代码逻辑层面必定要分清 业务逻辑被放置在model层,可以更好的复用和修改增长业务。

MVP

经过引入接口BaseView,让相应的视图组件如Activity,Fragment去实现BaseView,实现了视图层的独立,经过中间层Preseter实现了Model和View的彻底解耦。MVP完全解决了MVC中View和Controller傻傻分不清楚的问题,可是随着业务逻辑的增长,一个页面可能会很是复杂,UI的改变是很是多,会有很是多的case,这样就会形成View的接口会很庞大。

MVVM

MVP中咱们说过随着业务逻辑的增长,UI的改变多的状况下,会有很是多的跟UI相关的case,这样就会形成View的接口会很庞大。而MVVM就解决了这个问题,经过双向绑定的机制,实现数据和UI内容,只要想改其中一方,另外一方都可以及时更新的一种设计理念,这样就省去了不少在View层中写不少case的状况,只须要改变数据就行。

MVVM与DataBinding的关系?

MVVM是一种思想,DataBinding是谷歌推出的方便实现MVVM的工具。

看起来MVVM很好的解决了MVC和MVP的不足,可是因为数据和视图的双向绑定,致使出现问题时不太好定位来源,有可能数据问题致使,也有可能业务逻辑中对视图属性的修改致使。若是项目中打算用MVVM的话能够考虑使用官方的架构组件ViewModel、LiveData、DataBinding去实现MVVM。

三者如何选择?
  • 若是项目简单,没什么复杂性,将来改动也不大的话,那就不要用设计模式或者架构方法,只须要将每一个模块封装好,方便调用便可,不要为了使用设计模式或架构方法而使用。
  • 对于偏向展现型的app,绝大多数业务逻辑都在后端,app主要功能就是展现数据,交互等,建议使用mvvm。
  • 对于工具类或者须要写不少业务逻辑app,使用mvp或者mvvm均可。

70、SharedPrefrences的apply和commit有什么区别?

这两个方法的区别在于:

  1. apply没有返回值而commit返回boolean代表修改是否提交成功。

  2. apply是将修改数据原子提交到内存, 然后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘,所以,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操做,从而下降了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从必定程度上提升了不少效率。

  3. apply方法不会提示任何失败的提示。 因为在一个进程中,sharedPreference是单实例,通常不会出现并发冲突,若是对提交的结果不关心的话,建议使用apply,固然须要确保提交成功且有后续操做的话,仍是须要用commit的。

7一、Base6四、MD5是加密方法么?

Base64是什么?

Base64是用文本表示二进制的编码方式,它使用4个字节的文原本表示3个字节的原始二进制数据。 它将二进制数据转换成一个由64个可打印的字符组成的序列:A-Za-z0-9+/

MD5是什么?

MD5是哈希算法的一种,能够将任意数据产生出一个128位(16字节)的散列值,用于确保信息传输完整一致。咱们常在注册登陆模块使用MD5,用户密码能够使用MD5加密的方式进行存储。如:md5(hello world,32) = 5eb63bbbe01eeed093cb22bb8f5acdc3

加密,指的是对数据进行转换之后,数据变成了另外一种格式,而且除了拿到解密方法的人,没人能把数据转换回来。 MD5是一种信息摘要算法,它是不可逆的,不能够解密。因此它只能算的上是一种单向加密算法。 Base64也不是加密算法,它是一种数据编码方式,虽然是可逆的,可是它的编码方式是公开的,无所谓加密。

7二、HttpClient和HttpConnection的区别?

Http Client适用于web浏览器,拥有大量灵活的API,实现起来比较稳定,且其功能比较丰富,提供了不少工具,封装了http的请求头,参数,内容体,响应,还有一些高级功能,代理、COOKIE、鉴权、压缩、链接池的处理。   可是,正所以,在不破坏兼容性的前提下,其庞大的API也令人难以改进,所以Android团队对于修改优化Apache Http Client并不积极。(并在Android 6.0中抛弃了Http Client,替换成OkHttp)

HttpURLConnection对于大部分功能都进行了包装,Http Client的高级功能代码会较复杂,另外,HttpURLConnection在Android 2.3中增长了一些Https方面的改进(包括Http Client,二者都支持https)。且在Android 4.0中增长了response cache。当缓存被安装后(调用HttpResponseCache的install()方法),全部的HTTP请求都会知足如下三种状况:

  • 全部的缓存响应都由本地存储来提供。由于没有必要去发起任务的网络链接请求,全部的响应均可以马上获取到。
  • 视状况而定的缓存响应必需要有服务器来进行更新检查。好比说客户端发起了一条相似于 “若是/foo.png这张图片发生了改变,就将它发送给我” 这样的请求,服务器须要将更新后的数据进行返回,或者返回一个304 Not Modified状态。若是请求的内容没有发生,客户端就不会下载任何数据。
  • 没有缓存的响应都是由服务器直接提供的。这部分响应会在稍后存储到响应缓存中。

在Android 2.2版本以前,HttpClient拥有较少的bug,所以使用它是最好的选择。 而在Android 2.3版本及之后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,于是很是适用于Android项目。压缩和缓存机制能够有效地减小网络访问的流量,在提高速度和省电方面也起到了较大的做用。对于新的应用程序应该更加偏向于使用HttpURLConnection,由于在之后的工做当中Android官方也会将更多的时间放在优化HttpURLConnection上面。

7三、ActivityA跳转ActivityB而后B按back返回A,各自的生命周期顺序,A与B均不透明。

ActivityA跳转到ActivityB:
Activity A:onPause
Activity B:onCreate
Activity B:onStart
Activity B:onResume
Activity A:onStop
复制代码
ActivityB返回ActivityA:
Activity B:onPause
Activity A:onRestart
Activity A:onStart
Activity A:onResume
Activity B:onStop
Activity B:onDestroy
复制代码

7四、如何经过广播拦截和abort一条短信?

能够监听这条信号,在传递给真正的接收程序时,咱们将自定义的广播接收程序的优先级大于它,而且取消广播的传播,这样就能够实现拦截短信的功能了。

7五、BroadcastReceiver,LocalBroadcastReceiver 区别?

一、应用场景

一、BroadcastReceiver用于应用之间的传递消息;

二、而LocalBroadcastManager用于应用内部传递消息,比broadcastReceiver更加高效。

二、安全

一、BroadcastReceiver使用的Content API,因此本质上它是跨应用的,因此在使用它时必需要考虑到不要被别的应用滥用;

二、LocalBroadcastManager不须要考虑安全问题,由于它只在应用内部有效。

三、原理方面

(1) 与BroadcastReceiver是以 Binder 通信方式为底层实现的机制不一样,LocalBroadcastManager 的核心实现实际仍是 Handler,只是利用到了 IntentFilter 的 match 功能,至于 BroadcastReceiver 换成其余接口也无所谓,顺便利用了现成的类和概念而已。

(2) LocalBroadcastManager由于是 Handler 实现的应用内的通讯,天然安全性更好,效率更高。

7六、如何选择第三方,从那些方面考虑?

大方向:从软件环境作判断

性能是开源软件第一解决的问题。

一个好的生态,是一个优秀的开源库必备的,取决标准就是观察它是否一直在持续更新迭代,是否能及时处理github上用户提出来的问题。你们在社区针对这个开源库是否有比较活跃的探讨。

背景,该开源库由谁推出,由哪一个公司推出来的。

用户数和有哪些知名的企业落地使用

小方向:从软件开发者的角度作判断

是否解决了咱们现有问题或长期来看带来的维护成本。

公司有多少人会。

学习成本。

7七、简单说下接入支付的流程,是否本身接入过支付功能?

Alipay支付功能:

1.首先登陆支付宝开放平台建立应用,并给应用添加App支付功能, 因为App支付功能须要签约,所以须要上传公司信息和证件等资料进行签约。

2.签约成功后,须要配置秘钥。使用支付宝提供的工具生成RSA公钥和私钥,公钥须要设置到管理后台。

3.android studio集成

(1)copy jar包;
(2)发起支付请求,处理支付请求。
复制代码

7八、单例实现线程的同步的要求:

1.单例类确保本身只有一个实例(构造函数私有:不被外部实例化,也不被继承)。

2.单例类必须本身建立本身的实例。

3.单例类必须为其余对象提供惟一的实例。

7九、如何保证Service不被杀死?

Android 进程不死从3个层面入手:

A.提供进程优先级,下降进程被杀死的几率

方法一:监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,在用户解锁时将 Activity 销毁掉。

方法二:启动前台service。

方法三:提高service优先级:

在AndroidManifest.xml文件中对于intent-filter能够经过android:priority = "1000"这个属性设置最高优先级,1000是最高值,若是数字越小则优先级越低,同时适用于广播。

B. 在进程被杀死后,进行拉活

方法一:注册高频率广播接收器,唤起进程。如网络变化,解锁屏幕,开机等

方法二:双进程相互唤起。

方法三:依靠系统唤起。

方法四:onDestroy方法里重启service:service + broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,从新启动service;

C. 依靠第三方

根据终端不一样,在小米手机(包括 MIUI)接入小米推送、华为手机接入华为推送;其余手机能够考虑接入腾讯信鸽或极光推送与小米推送作 A/B Test。

80、说说ContentProvider、ContentResolver、ContentObserver 之间的关系?

ContentProvider:管理数据,提供数据的增删改查操做,数据源能够是数据库、文件、XML、网络等,ContentProvider为这些数据的访问提供了统一的接口,能够用来作进程间数据共享。

ContentResolver:ContentResolver能够为不一样URI操做不一样的ContentProvider中的数据,外部进程能够经过ContentResolver与ContentProvider进行交互。

ContentObserver:观察ContentProvider中的数据变化,并将变化通知给外界。

8一、如何导入外部数据库?

把原数据库包括在项目源码的 res/raw。

android系统下数据库应该存放在 /data/data/com.(package name)/ 目录下,因此咱们须要作的是把已有的数据库传入那个目录下。操做方法是用FileInputStream读取原数据库,再用FileOutputStream把读取到的东西写入到那个目录。

8二、LinearLayout、FrameLayout、RelativeLayout性能对比,为何?

RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子 View 2次onMeasure

RelativeLayout的子View若是高度和RelativeLayout不一样,则会引起效率问题,当子View很复杂时,这个问题会更加严重。若是能够,尽可能使用padding代替margin。

在不影响层级深度的状况下,使用LinearLayout和FrameLayout而不是RelativeLayout。

为何Google给开发者默认新建了个RelativeLayout,而本身却在DecorView中用了个LinearLayout?

由于DecorView的层级深度是已知并且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会下降层级深度,因此此时在根节点上用LinearLayout是效率最高的。而之因此给开发者默认新建了个RelativeLayout是但愿开发者能采用尽可能少的View层级来表达布局以实现性能最优,由于复杂的View嵌套对性能的影响会更大一些。

8三、scheme跳转协议

Android中的scheme是一种页面内跳转协议,经过定义本身的scheme协议,能够跳转到app中的各个页面

服务器能够定制化告诉app跳转哪一个页面

App能够经过跳转到另外一个App页面

能够经过H5页面跳转页面

8四、HandlerThread

一、HandlerThread原理

当系统有多个耗时任务须要执行时,每一个任务都会开启个新线程去执行耗时任务,这样会致使系统屡次建立和销毁线程,从而影响性能。为了解决这一问题,Google提出了HandlerThread,HandlerThread本质上是一个线程类,它继承了Thread。HandlerThread有本身的内部Looper对象,能够进行loopr循环。经过获取HandlerThread的looper对象传递给Handler对象,能够在handleMessage()方法中执行异步任务。建立HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调用run方法,建立Looper对象。当有耗时任务进入队列时,则不须要开启新线程,在原有的线程中执行耗时任务便可,不然线程阻塞。它在Android中的一个具体的使用场景是IntentService。因为HanlderThread的run()方法是一个无限循环,所以当明确不须要再使用HandlerThread时,能够经过它的quit或者quitSafely方法来终止线程的执行。

二、HanlderThread的优缺点

  • HandlerThread优势是异步不会堵塞,减小对性能的消耗。

  • HandlerThread缺点是不能同时继续进行多任务处理,要等待进行处理,处理效率较低。

  • HandlerThread与线程池不一样,HandlerThread是一个串队列,背后只有一个线程。

8五、IntentService

IntentService是一种特殊的Service,它继承了Service而且它是一个抽象类,所以必须建立它的子类才能使用IntentService。

原理

在实现上,IntentService封装了HandlerThread和Handler。当IntentService被第一次启动时,它的onCreate()方法会被调用,onCreat()方法会建立一个HandlerThread,而后使用它的Looper来构造一个Handler对象mServiceHandler,这样经过mServiceHandler发送的消息最终都会在HandlerThread中执行。

生成一个默认的且与主线程互相独立的工做者线程来执行全部传送至onStartCommand()方法的Intetnt。

生成一个工做队列来传送Intent对象给onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就没必要担忧多线程的问题。在全部的请求(Intent)都被执行完之后会自动中止服务,因此,你不须要本身去调用stopSelf()方法来中止。

该服务提供了一个onBind()方法的默认实现,它返回null。

提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工做队列,而后从工做队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent作相应的处理。

为何在mServiceHandler的handleMessage()回调方法中执行完onHandlerIntent()方法后要使用带参数的stopSelf()方法?

由于stopSel()方法会当即中止服务,而stopSelf(int startId)会等待全部的消息都处理完毕后才终止服务,通常来讲,stopSelf(int startId)在尝试中止服务以前会判断最近启动服务的次数是否和startId相等,若是相等就马上中止服务,不相等则不中止服务。

8六、如何将一个Activity设置成窗口的样式。

中配置:

android:theme="@android:style/Theme.Dialog"
复制代码

另外

android:theme="@android:style/Theme.Translucnt"
复制代码

是设置透明。

8七、Android中跨进程通信的几种方式

1:访问其余应用程序的Activity 如调用系统通话应用

Intent callIntent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
复制代码

2:Content Provider 如访问系统相册

3:广播(Broadcast) 如显示系统时间

4:AIDL服务

8八、显示Intent与隐式Intent的区别

对明确指出了目标组件名称的Intent,咱们称之为“显式Intent”。

对于没有明确指出目标组件名称的Intent,则称之为“隐式 Intent”。

对于隐式意图,在定义Activity时,指定一个intent-filter,当一个隐式意图对象被一个意图过滤器进行匹配时,将有三个方面会被参考到:

动做(Action)

类别(Category ['kætɪg(ə)rɪ] )

数据(Data )

<activity android:name=".MainActivity"  android:label="@string/app_name">
            <intent-filter>
                <action android:name="com.wpc.test" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="image/gif"/>
            </intent-filter>
</activity>
复制代码

8九、Android Holo主题与MD主题的理念,以及你的见解

Holo Theme

Holo Theme 是 Android Design 的最基础的呈现方式。由于是最为基础的 Android Design 呈现形式,每一台 Android 4.X 的手机系统内部都有集成 Holo Theme 须要的控件,即开发者不须要本身设计控件,而是直接从系统里调用相应的控件。在 UI 方面没有任何的亮点,和 Android4.X 的设置/电话的视觉效果极度统一。由此带来的好处显而易见,这个应用做为 Android 应用的辨识度极高,且彻底不可能与系统风格产生冲突。

Material Design

Material design实际上是单纯的一种设计语言,它包含了系统界面风格、交互、UI,更加专一拟真,更加大胆丰富的用色,更加丰富的交互形式,更加灵活的布局形式

1.鲜明、形象的界面风格,

2.色彩搭配使得应用看起来很是的大胆、充满色彩感,凸显内容

3.Material design对于界面的排版很是的重视

4.Material design的交互设计上采用的是响应式交互,这样的交互设计能把一个应用从简单展示用户所请求的信息,提高至能与用户产生更强烈、更具体化交互的工具。

90、如何让程序自动启动?

定义一个Braodcastreceiver,action为BOOT——COMPLETE,接受到广播后启动程序。

9一、Fragment 在 ViewPager 里面的生命周期,滑动 ViewPager 的页面时 Fragment 的生命周期的变化。

9二、如何查看模拟器中的SP与SQList文件。如何可视化查看布局嵌套层数与加载时间。

9三、各大平台打包上线的流程与审核时间,常见问题(主流的应用市场说出3-4个)

9四、屏幕适配的处理技巧都有哪些?

1、为何要适配

为了保证用户得到一致的用户体验效果,使得某一元素在Android不一样尺寸、不一样分辨率的、不一样系统的手机上具有相同的显示效果,可以保持界面上的效果一致,咱们须要对各类手机屏幕进行适配!

  • Android系统碎片化:基于Google原生系统,小米定制的MIUI、魅族定制的flyme、华为定制的EMUI等等;
  • Android机型屏幕尺寸碎片化:5寸、5.5寸、6寸等等;
  • Android屏幕分辨率碎片化:320x480、480x800、720x1280、1080x1920等。
2、基本概念
  • 像素(px):像素就是手机屏幕的最小构成单元,px = 1像素点 通常状况下UI设计师的设计图会以px做为统一的计量单位。
  • 分辨率:手机在横向、纵向上的像素点数总和 通常描述成 宽*高 ,即横向像素点个数 * 纵向像素点个数(如1080 x 1920),单位:px。
  • 屏幕尺寸:手机对角线的物理尺寸。单位 英寸(inch),一英寸大约2.54cm 常见的尺寸有4.7寸、5寸、5.5寸、6寸。
  • 屏幕像素密度(dpi):每英寸的像素点数,例如每英寸内有160个像素点,则其像素密度为160dpi,单位:dpi(dots per inch)。
  • 标准屏幕像素密度(mdpi): 每英寸长度上还有160个像素点(160dpi),即称为标准屏幕像素密度(mdpi)。
  • 密度无关像素(dp):与终端上的实际物理像素点无关,能够保证在不一样屏幕像素密度的设备上显示相同的效果,是安卓特有的长度单位,dp与px的转换:1dp = (dpi / 160 ) * 1px。
  • 独立比例像素(sp):字体大小专用单位 Android开发时用此单位设置文字大小,推荐使用12sp、14sp、18sp、22sp做为字体大小。
3、适配方案

适配的最多的3个分辨率:1280720,19201080,800*480。

解决方案:

对于Android的屏幕适配,我认为能够从如下4个方面来作:

一、布局组件适配

  • 请务必使用密度无关像素 dp 或独立比例像素 sp 单位指定尺寸。
  • 使用相对布局或线性布局,不要使用绝对布局
  • 使用wrap_content、match_parent、权重
  • 使用minWidth、minHeight、lines等属性

dimens使用:

不一样的屏幕尺寸能够定义不一样的数值,或者是不一样的语言显示咱们也能够定义不一样的数值,由于翻译后的长度通常都不会跟中文的一致。此外,也能够使用百分比布局或者AndroidStudio2.2的新特性约束布局。

二、布局适配

使用限定符(屏幕密度限定符、尺寸限定符、最小宽度限定符、布局别名、屏幕方向限定符)根据屏幕的配置来加载相应的UI布局。

三、图片资源适配

使用自动拉伸图.9png图片格式使图片资源自适应屏幕尺寸。

普通图片和图标:

建议按照官方的密度类型进行切图便可,但通常咱们只需xxhdpi或xxxhdpi的切图便可知足咱们的需求;

四、代码适配:

在代码中使用Google提供的API对设备的屏幕宽度进行测量,而后按照需求进行设置。

五、接口配合:

本地加载图片前判断手机分辨率或像素密度,向服务器请求对应级别图片。

9五、断点续传实现?

在本地下载过程当中要使用数据库实时存储到底存储到文件的哪一个位置了,这样点击开始继续传递时,才能经过HTTP的GET请求中的setRequestProperty("Range","bytes=startIndex-endIndex");方法能够告诉服务器,数据从哪里开始,到哪里结束。同时在本地的文件写入时,RandomAccessFile的seek()方法也支持在文件中的任意位置进行写入操做。最后经过广播或事件总线机制将子线程的进度告诉Activity的进度条。关于断线续传的HTTP状态码是206,即HttpStatus.SC_PARTIAL_CONTENT。

9六、项目中遇到哪些难题,最终你是如何解决的

9七、Activity正常和异常状况下的生命周期

9八、关于< include >< merge >< stub >三者的使用场景

9九、Android对HashMap作了优化后推出的新的容器类是什么?

赞扬

若是这个库对您有很大帮助,您愿意支持这个项目的进一步开发和这个项目的持续维护。你能够扫描下面的二维码,让我喝一杯咖啡或啤酒。很是感谢您的捐赠。谢谢!


Contanct Me

● 微信 && 微信群:

欢迎关注个人微信:bcce5360。因为微信群人数太多没法生成群邀二维码,因此麻烦你们想进微信群的朋友们,加我微信拉你进群(PS:微信群的学习氛围与各项福利将会超乎你的想象)

● QQ群:

2千人QQ群,Awesome-Android学习交流群,QQ群号:959936182, 欢迎你们加入~

About me

很感谢您阅读这篇文章,但愿您能将它分享给您的朋友或技术群,这对我意义重大。

但愿咱们能成为朋友,在 Github掘金上一块儿分享知识。