指南

Activity

Service

Broadcast

ContentProvider

Fragment

View

View绘制

View事件分发

自定义View

View滑动

控件

RecyclerView

ListView

ViewPager

动画

Bitmap && Drawable

Android线程与进程

Handler/Looper

Binder

序列化

进程保活

AsyncTask

HandlerThread

IntentService

IPC

线程池

Android优化

ANR

1. ANR是什么?如何避免和解决ANR?

ANR:Application Not Responding,即应用无响应。一般有以下三种:

  • KeyDispatchTimeout:5s
  • BroadcatTimeout:10s
  • ServiceTimeout:20s

造成Timeout的原因一般有两种:

  • 主线程阻塞在了某个消息中

  • 当前事件正在被处理但是没有被处理完

操作阻塞的原因可能是:

  • 耗时的网络操作
  • 大量的数据读写
  • 数据库操作
  • 硬件操作
  • 线程等待
  • 发生了死锁
  • 动画耗时
  • Cpu负载高

问题定位:

  • ANR产生时,系统会生成一个tarces.txt的文本文件放在/data/anr下,最新的ANR信息在最开始的位置。通过ADB命令adb pull data/anr/traces.txt .可以导出到本地分析。
  • 使用Android Studio中的Profile工具可以方便的得到每个方法的运行时间
  • 使用Android SDK中提供的Debug类:
    1. 在开始的记录的点写上代码Debug.startMethodTracing("TAG");
    2. 在终止记录的点写上代码Debug.stopMethodTracing();
    3. 通过adb pull /data/tracePath.trace导出文件并使用Android Studio打开分析

解决方法:

  • 不要在主线程中去做耗时操作,将耗时操作放在子线程中去。通过Thread、HandlerThread、IntentService、AsyncTask
  • 同样由于Service/Broadcast运行在主线程,Service中也不能做耗时操作
  • 在使用Thread或者HandlerThread时,可以尝试调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置较低优先级,否则依然会降低程序响应,因为默认Thread的优先级和主线程相同。
  • 任何UI线程中的方法都应该简短快捷,类似调整Bitmap大小这种需要长时间计算的操作,都应该执行在工作线程中。
  • BroadcastReceiver中的onReceive()方法如果必须执行耗时操作,建议在这个方法中开启IntentService来执行耗时操作。

内存泄漏memory leak

1. 内存泄漏的原因、场景、解决方法?

根本原因:长生命周期的对象持有短生命周期的对象,导致短生命周期对象就无法及时释放。

泄漏场景:

  • 非静态内部类的静态实例
    非静态内部类会持有外部类的引用,如果这个非静态内部类的实例恰好是个静态实例,那么这个实例就会长时间的存在,从而导致外部类长时间被引用,就无法被回收,从而造成外部类的内存泄漏。

  • 匿名内部类
    匿名内部类同样会持有外部类的引用,如果这个匿名内部类中做了耗时操作,就会导致外部类长时间被引用从而无法回收。

  • Handler内存泄漏

    Handler内存泄漏也可以归纳为非静态内部类导致的,Handler发送的消息Message首先会将自己的target指向当前Handler对象,然后这个Message会被加入到Looper中的MessageQueue中等待被处理。如果消息长时间得不到处理,Handler就会被一直引用,从而外部类也就一直被引用,导致内存泄漏。这种情况下建议:

    1. 使用静态Handler
    2. 在退出时移除消息队列中的消息
    3. 外部类引用使用弱引用处理
  • Context内存泄漏
    根据场景确定使用Activity的Context还是ApplicationContext,因为两者生命周期不同,对于不必须使用Activity的Context的场景(Dialog),一律采用ApplicationContext。单例模式是最常见的发生此泄漏的场景。比如传入一个Activity的Context被静态类引用,导致无法回收。

  • 静态View内存泄漏

    使用静态View可以避免每次启动Activity都去读取并渲染View,但是View会持有Activity的引用,导致无法回收。解决办法时在Activity销毁的时候将静态View设置为null(View一旦被加载到界面上会持有一个Context对象的引用,这里就是Activity。)

  • WebView导致的内存泄漏
    WebView只要使用一次,内存就不会被释放,所以WebView都存在内存泄漏的问题。通常的解决办法时为WebView单独打开一个进程,使用AIDL进行通信,根据业务需求在合适的时机释放掉。

  • 资源对象未关闭

  • 集合中的对象未清理

  • Bitmap内存泄漏

    避免静态变量持有大的Bitmap对象。

  • 监听器未关闭
    很多需要register和unregister的系统服务要在合适的时候进行unregister,手动添加的listener也要及时移除。

检测方法:

  • LeakCanary

OOM (out of memory)

冷启动&&热启动

性能优化

UI优化

其它

Context

1. 谈谈你对Android中Context的理解?

Context:包含上下文信息的一个参数。Android 中的 Context 分三种:

  • Application Context

  • Activity Context

  • Service Context

它描述的是一个应用程序环境的信息, 通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作, 例如: 启动一个 Activity, 发送广播, 接受 Intent 信息等。

Application

权限

Android中的强、弱、软、虚应用

LruCache && DiskLruCache

第三方库

OkHttp

Glide

1. 说说View的绘制流程

  1. Measure过程:View的绘制其实就是一个深度遍历的过程。这里有一个MeasureSpec的概念,每一个View都有一个MeasureSpec,它由父View根据自己的MeasureSpec和子View的LayoutParam共同决定。MeasureSpec有三个取值:
    1. MeasureSpec. UNSPECIFIED:不限制View大小
    2. MeasureSpec.EXACTLY:
    3. MeasureSpec.AT_MOST:
  2. Layout过程:
  3. Draw过程:
    1. Draw the background
    2. If necessary, save the canvas' layers to prepare for fading
    3. Draw view's content
    4. Draw children
    5. If necessary, draw the fading edges and restore layers
    6. Draw decorations (scrollbars for instance)

2. 说说Activity的启动模式

启动模式涉及到一个Task的概念,Task说的是为了完成一个任务的一系列的Activity的集合,这些Activity可以是来自不同的应用的。比如一个应用需要写一封邮件,它用Intent去打开了邮件这个应用的写邮件的MailActivity,这个Activity就可以和其它Activity同属一个Task。

启动模式有四种:

  1. standard
  2. singleTask
  3. singleTop
  4. singleInstance

标记位有三个:

  1. FLAG_ACTIVITY_NEW_TASK:
  2. FLAG_ACTIVITY_SINGLE_TOP:
  3. FLAG_ACTIVITY_CLEAR_TOP:

标记位优先级>启动模式

3. 说说Activity的生命周期

  1. onCreate-->onStart()-->onResume()-->onPause()-->onStop()-->onDestrory()
    -->onRestart()
  2. 正常关闭情况下onSaveInstanceState() 以及 onRestoreInstanceState()这两个方法是不会被调用的。它们只会在Activity不正常关闭下调用。我们说的视图恢复就是指的不正常关闭时候,Activity再次打开的时候要让用户感觉到Activity并没有被关闭。
  3. 建议onStop()中保存数据

4. 说说View事件分发

手指在屏幕的动作被抽象成了MotionEvent对象,根据不同情境分成了MotionEvent.ACTION_DOWN、MotionEvent.ACTION_POINTER_DOWN、MotionEvent.ACTION_MOVE、MotionEvent.ACTION_UP、MotionEvent.ACTON_CANCLE。事件分发主要就是当ACTION_DOWN以及ACTION_POINTER_DOWN两个事件到来时寻找新的TouchTarget的过程。主要有三个大的方法参与这个过程:

  1. dispatchTouchEvent()
  2. onInterceptTouchEvent() (ViewGroup独有)
  3. onTouchEvent()

其中dispatchTouchEvent负责寻找到一个新的TouchTarget,,并把事件交给TouchTarget。onInterceptTouchEvent()指示当前ViewGroup是否拦截此次事件。onTouchEvent()处理事件,它的返回代表当前事件是否被这个View消耗。

onTouch()--> onTouchEvent()-->onClick()

5. 内存泄漏

你可能感兴趣的:(指南)