写点什么

互联网 BAT 大厂(百度、美团等,作为 Android 开发程序员

用户头像
Android架构
关注
发布于: 刚刚

public class MainActivity extends AppCompatActivity {private final Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {// ...}};

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new Thread(new Runnable() {@Overridepublic void run() {// ...handler.sendEmptyMessage(0x123);}});}}


1、从 Android 的角度当 Android 应用程序启动时,该应用程序的主线程会自动创建一个 Looper 对象和与之关联的 MessageQueue。当主线程中实例化一个 Handler 对象后,它就会自动与主线程 Looper 的 MessageQueue 关联起来。所有发送到 MessageQueue 的 Message 都会持有 Handler 的引用,所以 Looper 会据此回调 Handle 的 handleMessage()方法来处理消息。只要 MessageQueue 中有未处理的 Message,Looper 就会不断的从中取出并交给 Handler 处理。另外,主线程的 Looper 对象会伴随该应用程序的整个生命周期。2、 Java 角度在 Java 中,非静态内部类和匿名类内部类都会潜在持有它们所属的外部类的引用,但是静态内部类却不会。

对上述的示例进行分析,当 MainActivity 结束时,未处理的消息持有 handler 的引用,而 handler 又持有它所属的外部类也就是 MainActivity 的引用。这条引用关系会一直保持直到消息得到处理,这样阻止了 MainActivity 被垃圾回收器回收,从而造成了内存泄漏。

**解决方法:**将 Handler 类独立出来或者使用静态内部类,这样便可以避免内存泄漏。

  • 4.线程造成的内存泄漏

示例:AsyncTask 和 RunnableAsyncTask 和 Runnable 都使用了匿名内部类,那么它们将持有其所在 Activity 的隐式引用。如果任务在 Activity 销毁之前还未完成,那么将导致 Activity 的内存资源无法被回收,从而造成内存泄漏。**解决方法:**将 AsyncTask 和 Runnable 类独立出来或者使用静态内部类,这样便可以避免内存泄漏。

  • 5.资源未关闭造成的内存泄漏

对于使用了 BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap 等资源,应该在 Activity 销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄漏。1)比如在 Activity 中 register 了一个 BraodcastReceiver,但在 Activity 结束后没有 unregister 该 BraodcastReceiver。2)资源性对象比如 Cursor,Stream、File 文件等往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java 虚拟机内,还存在于 java 虚拟机外。如果我们仅仅是把它的引用设置为 null,而不关闭它们,往往会造成内存泄漏。3)对于资源性对象在不使用的时候,应该调用它的 close()函数将其关闭掉,然后再设置为 null。在我们的程序退出时一定要确保我们的资源性对象已经关闭。4)Bitmap 对象不在使用时调用 recycle()释放内存。2.3 以后的 bitmap 应该是不需要手动 recycle 了,内存已经在 java 层了。

  • 6.使用 ListView 时造成的内存泄漏

初始时 ListView 会从 BaseAdapter 中根据当前的屏幕布局实例化一定数量的 View 对象,同时 ListView 会将这些 View 对象缓存起来。当向上滚动 ListView 时,原先位于最上面的 Item 的 View 对象会被回收,然后被用来构造新出现在下面的 Item。这个构造过程就是由 getView()方法完成的,getView()的第二个形参 convertView 就是被缓存起来的 Item 的 View 对象(初始化时缓存中没有 View 对象则 convertView 是 null)。构造 Adapter 时,没有使用缓存的 convertView。**解决方法:**在构造 Adapter 时,使用缓存的 convertView。

  • 7.集合容器中的内存泄露

我们通常把一些对象的引用加入到了集合容器(比如 ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是 static 的话,那情况就更严重了。解决方法:在退出程序之前,将集合里的东西 clear,然后置为 null,再退出程序。

  • 8.WebView 造成的泄露

当我们不要使用 WebView 对象时,应该调用它的 destory()函数来销毁它,并释放其占用的内存,否则其长期占用的内存也不能被回收,从而造成内存泄露。解决方法:为 WebView 另外开启一个进程,通过 AIDL 与主线程进行通信,WebView 所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。


  1. ANR 定位和修正


如果开发机器上出现问题,我们可以通过查看/data/anr/traces.txt 即可,最新的 ANR 信息在最开始部分。

  • 主线程被 IO 操作(从 4.0 之后网络 IO 不允许在主线程中)阻塞。

  • 主线程中存在耗时的计算

  • 主线程中错误的操作,比如 Thread.wait 或者 Thread.sleep 等 Android 系统会>* 监控程序的响应状况,一旦出现下面两种情况,则弹出 ANR 对话框

  • 应用在 5 秒内未响应用户的输入事件(如按键或者触摸)

  • BroadcastReceiver 未在 10 秒内完成相关的处理

  • Service 在特定的时间内无法处理完成 20 秒修正

  • 使用 AsyncTask 处理耗时 IO 操作。

  • 使用 Thread 或者 HandlerThread 时,调用 Process.setThreadPriority(Process.THREADPRIORITYBACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认 Thread 的优先级和主线程相同。

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

  • Activity 的 onCreate 和 onResume 回调中尽量避免耗时的代码

  • BroadcastReceiver 中 onReceive 代码也要尽量减少耗时,建议使用 IntentService 处理。


  1. 什么情况导致 oom(乐视、美团)


这个跟 11 好像差不多


  1. Android Service 与 Activity 之间通信的几种方式


  • 通过 Binder 对象

  • 通过 Intent

  • 通过 Broadcast 广播

  • 自定义接口回调


  1. Android 各个版本 API 的区别


http://blog.csdn.net/u012964796/article/details/50662564


  1. 如何保证一个后台服务不被杀死,比较省电的方式是什么?(百度)


  • 双进程守护(就是开启二个 service,二个 service 是不同的进程中,用 aidl 监听,有一个 service 杀死了,另一个 service 监听到了就重新启动刚杀死的 service),这个有时间时专门写文章介绍;

  • service 绑定通知栏成为前台服务,

  • 还有一个就是锁屏时启动一个像素的 activity,哈哈,好像某应用就是这么干的;

  • AlarmManager 不断启动 service

  • 通过 jni 调用,在 c 层启动多进程


  1. Requestlayout, onlayout, onDraw, DrawChild 区别与联系(猎豹)


requestLayout()方法 :会导致调用 measure()过程 和 layout()过程 。 将会根据标志位判断是否需要 ondrawonLayout()方法(如果该 View 是 ViewGroup 对象,需要实现该方法,对每个子视图进行布局)调用 onDraw()方法绘制视图本身 (每个 View 都需要重载该方法,ViewGroup 不需要实现该方法)drawChild()去重新回调每个子视图的 draw()方法


  1. invalidate()和 postInvalidate() 的区别及使用(百度)


postInvalidate() 方法在非 UI 线程中调用,通知 UI 线程重绘。invalidate() 方法在 UI 线程中调用,重绘当前 UI。


  1. Android 动画框架实现原理


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


  1. Android 为每个应用程序分配的内存大小是多少?(美团)


android 程序内存一般限制在 16M,也有的是 24M


  1. Android View 刷新机制(百度、美团)


由 ViewRoot 对象的 performTraversals()方法调用 draw()方法发起绘制该 View 树,值得注意的是每次发起绘图时,并不会重新绘制每个 View 树的视图,而只会重新绘制那些“需要重绘”的视图,View 类内部变量包含了一个标志位 DRAWN,当该视图需要重绘时,就会为该 View 添加该标志位。

调用流程 :

mView.draw()开始绘制,draw()方法实现的功能如下:

绘制该 View 的背景为显示渐变框做一些准备操作(见 5,大多数情况下,不需要改渐变框)调用 onDraw()方法绘制视图本身 (每个 View 都需要重载该方法,ViewGroup 不需要实现该方法)调用 dispatchDraw ()方法绘制子视图(如果该 View 类型不为 ViewGroup,即不包含子视图,不需要重载该方法)值得说明的是,ViewGroup 类已经为我们重写了 dispatchDraw ()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。


  1. LinearLayout 对比 RelativeLayout(百度)(Ricky)


RelativeLayout 会让子 View 调用 2 次 onMeasure,LinearLayout 在有 weight 时,也会调用子 View2 次 onMeasure,RelativeLayout 的子 View 如果高度和 RelativeLayout 不同,则会引发效率问题,当子 View 很复杂时,这个问题会更加严重。如果可以,尽量使用 padding 代替 margin。在不影响层级深度的情况下,使用 LinearLayout 和 FrameLayout 而不是 RelativeLayout。最后再思考一下文章开头那个矛盾的问题,为什么 Google 给开发者默认新建了个 RelativeLayout,而自己却在 DecorView 中用了个 LinearLayout。因为 DecorView 的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用 RelativeLayout 并不会降低层级深度,所以此时在根节点上用 LinearLayout 是效率最高的。而之所以给开发者默认新建了个 RelativeLayout 是希望开发者能采用尽量少的 View 层级来表达布局以实现性能最优,因为复杂的 View 嵌套对性能的影响会更大一些。


  1. 优化自定义 view(百度、乐视、小米)


为了加速你的 view,对于频繁调用的方法,需要尽量减少不必要的代码。先从 onDraw 开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致 GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。

你还需要尽可能的减少 onDraw 被调用的次数,大多数时候导致 onDraw 都是因为调用了 invalidate().因此请尽量减少调用 invaildate()的次数。如果可能的话,尽量调用含有 4 个参数的 invalidate()方法而不是没有参数的 invalidate()。没有参数的 invalidate 会强制重绘整个 view。

另外一个非常耗时的操作是请求 layout。任何时候执行 requestLayout(),会使得 Android UI 系统去遍历整个 View 的层级来计算出每一个 view 的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持 View 的层级是扁平化的,这样对提高效率很有帮助。

如果你有一个复杂的 UI,你应该考虑写一个自定义的 ViewGroup 来执行他的 layout 操作。与内置的 view 不同,自定义的 view 可以使得程序仅仅测量这一部分,这避免了遍历整个 view 的层级结构来计算大小。这个 PieChart 例子展示了如何继承 ViewGroup 作为自定义 view 的一部分。PieChart 有子 views,但是它从来不测量它们。而是根据他自身的 layout 法则,直接设置它们的大小。


  1. ContentProvider(乐视)


http://blog.csdn.net/coder_pig/article/details/47858489https://www.jianshu.com/p/f5ec75a9cfea


  1. fragment 生命周期



  1. volley 解析(美团、乐视)


https://www.jianshu.com/p/15e6209d2e6f


  1. Android Glide 源码解析


http://blog.csdn.net/guolin_blog/article/details/53759439


  1. Android 属性动画特性(乐视、小米)


https://www.jianshu.com/p/8076fe970a0c


  1. Handler 机制及底层实现


http://blog.csdn.net/lmj623565791/article/details/38377229


  1. Binder 机制及底层实现


http://blog.csdn.net/weijinqian0/article/details/52233529

Java 基础

  1. 接口的意义(百度)


1、重要性:在 Java 语言中, abstract class 和 interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了 Java 强大的 面向对象能力。

2、简单、规范性:如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口不仅告诉开发人员你需要实现那些业务,而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)。

3、维护、拓展性:比如你要做一个画板程序,其中里面有一个面板类,主要负责绘画功能,然后你就这样定义了这个类。可是在不久将来,你突然发现这个类满足不了你了,然后你又要重新设计这个类,更糟糕是你可能要放弃这个类,那么其他地方可能有引用他,这样修改起来很麻烦。

如果你一开始定义一个接口,把绘制功能放在接口里,然后定义类时实现这个接口,然后你只要用这个接口去引用实现它的类就行了,以后要换的话只不过是引用另一个类而已,这样就达到维护、拓展的方便性。

4、安全、严密性:接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些(一般软件服务商考虑的比较多)。


  1. 抽象类的意义(乐视)


抽象类往往用来表征对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。具体分析如下:

1.因为抽象类不能实例化对象,所以必须要有子类来实现它之后才能使用。这样就可以把一些具有相同属性和方法的组件进行抽象,这样更有利于代码和程序的维护。

2.当又有一个具有相似的组件产生时,只需要实现该抽象类就可以获得该抽象类的那些属性和方法。


  1. 内部类的作用(百度,乐视)


定义:放在一个类的内部的类我们就叫内部类。

作用:

1.内部类可以很好的实现隐藏,一般的非内部类,是不允许有 private 与 protected 权限的,但内部类可以

2.内部类拥有外围类的所有元素的访问权限

3.可是实现多重继承

4.可以避免修改接口而实现同一个类中两种同名方法的调用。


  1. 父类的静态方法能否被子类重写,为什么?(猎豹)


父类的静态方法是不能被子类重写的,其实重写只能适用于实例方法,不能用于静态方法,对于上面这种静态方法而言,我们应该称之为隐藏。

Java 静态方法形式上可以重写,但从本质上来说不是 Java 的重写。因为静态方法只与类相关,不与具体实现相关。声明的是什么类,则引用相应类的静态方法(本来静态无需声明,可以直接引用)。并且 static 方法不是后期绑定的,它在编译期就绑定了。换句话说,这个方法不会进行多态的判断,只与声明的类有关。


  1. 举 1-2 个排序算法,并使用 java 代码实现(美团)

  2. 列举 java 的集合和继承关系(百度、美团)

  3. java 虚拟机的特性(百度、乐视)


Java 语言的一个非常重要的特点就是与平台的无关性。而使用 Java 虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入 Java 语言虚拟机后,Java 语言在不同平台上运行时不需要重新编译。Java 语言使用模式 Java 虚拟机屏蔽了与具体平台相关的信息,使得 Java 语言编译程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java 虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。


  1. 哪些情况下的对象会被垃圾回收机制处理掉(乐视、美团、小米)


Java 垃圾回收机制最基本的做法是分代回收。内存中的区域被划分成不同的世代,对象根据其存活的时间被保存在对应世代的区域中。一般的实现是划分成 3 个世代:年轻、年老和永久。内存的分配是发生在年轻世代中的。当一个对象存活时间足够长的时候,它就会被复制到年老世代中。对于不同的世代可以使用不同的垃圾回收算法。进行世代划分的出发点是对应用中对象存活时间进行研究之后得出的统计规律。一般来说,一个应用中的大部分对象的存活时间都很短。比如局部变量的存活时间就只在方法的执行过程中。基于这一点,对于年轻世代的垃圾回收算法就可以很有针对性。(1)超出对象的引用句柄的作用域时,这个引用句柄引用的对象就变成垃圾。

(2)没有超出对象的引用句柄的作用域时,给这个引用句柄赋值为空时,这个引用句柄引用的对象就变成垃圾。

(3)创建匿名对象时,匿名对象用完以后即成垃圾。


  1. 进程和线程的区别(猎豹)


进程和线程都是一个时间段的描述,是 CPU 工作时间段的描述,不过是颗粒大小不同。

  1. 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

  2. 线程的划分尺度小于进程,使得多线程程序的并发性高。

  3. 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

  4. 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

  5. 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。


  1. Java 中==和 equals 的区别, equals 和 hashCode 的区别(乐视)


http://blog.csdn.net/tiantiandjava/article/details/46988461


  1. ArrayList 和 HashMap 的实现原理(美团,百度)https://www.jianshu.com/p/f174d49b391c

  2. java 中 int char long 各占多少字节数


short 2 个字节 int 4 个字节 long 8 个字节


  1. java int 与 integer 的区别


http://blog.csdn.net/chenliguan/article/details/53888018


  1. string stringbuffer stringbuilder 区别(小米、乐视、百度)


String:适用于少量的字符串操作的情况 StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况(非线程安全)StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况(线程安全)在大部分情况下 StringBuilder > StringBufferhttps://www.cnblogs.com/su-feng/p/6659064.html


  1. Java 多态(乐视)


http://blog.csdn.net/Jian_Yun_Rui/article/details/52937791


  1. 什么导致线程阻塞(58、美团)


http://blog.csdn.net/sinat_22013331/article/details/45740641


  1. 抽象类接口区别(360)


https://www.cnblogs.com/yongjiapei/p/5494894.html


  1. 容器类之间的区别(乐视、美团)


https://www.cnblogs.com/sunliming/archive/2011/04/05/2005957.html


  1. Java 中 HashMap 和 HashTable 的区别(乐视、小米)


https://www.cnblogs.com/lchzls/p/6714335.htmlhttp://blog.csdn.net/u012050154/article/details/50905364


  1. ArrayMap VS HashMap


http://blog.csdn.net/vansbelove/article/details/52422087

数据结构与算法

  1. 堆和栈在内存中的区别是什么(数据结构方面以及实际实现方面)

  2. 最快的排序算法是哪个?给阿里 2 万多名员工按年龄排序应该选择哪个算法?堆和树的区别;写出快排代码;链表逆序代码(阿里)

  3. 求 1000 以内的水仙花数以及 40 亿以内的水仙花数(百度)

  4. 子串包含问题(KMP 算法)写代码实现

  5. 万亿级别的两个 URL 文件 A 和 B,如何求出 A 和 B 的差集 C,(Bit 映射->hash 分组->多文件读写效率->磁盘寻址以及应用层面对寻址的优化)

  6. 蚁群算法与蒙特卡洛算法

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
互联网BAT大厂(百度、美团等,作为Android开发程序员