Android培训

亿元级外企Android培训企业

  • 全国服务监督电话4001118989
  • 做为一个Android开发程序员,这些Android基本功你会吗?

    发布:Android培训  来源:Android教程  时间: 2017年05月17日

  • 做为一个Android开发程序员,这些Android基本功你会吗?...

  • 1. app被杀死怎么启动

    (1) 场景:

    用户按了home键,系统内存不足,导致应用被强杀;

    (2) 可能引起的问题:

    当类中设置了static变量而在A类中初始化,在B类页面调用,应用被强杀时,再点击应用回到B类,由于static尚未初始化,会导致空指针,应用崩溃;

    (3) 被强杀后应用变量情况:

    当app在后台被强杀后,app中所有变量都被清空(包括application实例),整个app进程都被销毁,但Activity的栈信息依然保存着,所以在回到应用时还能得知页面的打开顺序;就用被强杀时,会自动调用onSaveInstance方法保存一些核心变量。

    (4) 解决办法–重走应用流程

    if(isForceKilled) { 
    startActivity(new Intent(this, SplashActivity.class)); 
    }

    2. 如何完全退出一个应用

    (1)做一个自定义的栈来管理相应的Activity,需要退出时再pop出栈,相应Activity finish

    (2)BaseActivity + RxBus(EventBus)

    如果采用Rxjava开发,直接采用RxBus, 也可以自己写个广播,所有的类都继承自BaseActivity。 
    直接用RxBus发送退出应用的消息,在BaseActivty接收消息,再调用finish();所有栈内继承于BaseActivity的Activity都会接收到事件,并调用finish结束Activity。在finish之后还可以使用System.exit(0),这样会提示虚拟机kill掉进程。

    3. 耗电太多怎么优化

    (1)应用耗电主要体现在以下几方面:

    1) 常规使用:大数据量的传输(IO),不停的在网络间切换(网络请求操作);解析大量的文本数据;
    2) 对设备的频繁唤醒:在Android中AlarmManager可唤醒设备,WakeLock能让CPU保持唤醒状态,这两者不恰当使用,没有合理释放掉,将会使系统长时间无法进入休眠,导致高耗电;
    3) GPS:对GPS设备的使用控制,GPS实时性所以电量消耗也比较严重;
    4) 传感器和屏幕;

    (2)优化途径:

    1) 在需要网络连接的程序中,先检查网络连接是否正常,若没有网络连接,就不需要执行相应程序;在蜂窝移动网络下,批量执行网络请求,尽量避免频繁间隔网络请求;应该尽量减少移动网络下数据传输,多在WiFi环境下传输数据; 
    2) 使用效率高的数据格式和解析方法,如JSON和Protobuf; 
    3) 在进行大数据下载时,尽量使用GZIP方式下载;
    4) 回收Java对象,特别是较大的java对象,使用reset方法,对定位要求不太高的不要使用GPS定位,使用wifi和移动网络cell定位;尽量不要使用浮点运算;获取屏幕尺寸等信息可以使用缓存技术;使用AlarmManager定时启动服务替代使用sleep方式的定时任务。
    5)使用JobScheduler来管理后台工作,将一些不是特别紧急的任务放到更合适的时机批量处理;
    6) 监控电池当前的电量和充放电状态,在程序中做相应参数设置以减少耗电量。

    4.怎么统计crash

    可集成第三方sdk进行统计,如友盟、腾讯Bugly,可以分析出每个版本出现的bug数,每个bug出现的时间、频次、机型、应用版本、bug出现的位置

    5.怎么减少用户流量消耗

    (1)网络监控:

    1) Android Studio自带的Network Monitor可看出时间段内网络请求数量及访问速率; 
    2) 使用代理工具,如Wireshark, Fiddler, Charles,可以查看每一次网络请求,传输的数据量;

    (2)网络优化:

    1) 使用GZIP压缩进行数据传输,不仅可以减少流量消耗,还可减少传输时间; 
    2) 使用IP直连,而不用域名,省去DNS解析过程; 
    3) 图片方面:图片使用WebP格式,可节省流量;使用压缩图,图片按需加载,只有用户查看大图时才加载原图;图片上传时,采用分片传输,每个分片失败重传,根据网络类型及传输过程中的变化动态修改分片大小; 
    4) 协议层优化,Http1.1引入了“持久连接”,多个请求被复用,无需重建TCP连接;Http2引入了“多头”、头信息压缩、服务器推送等; 
    5) 合并网络请求,减少请求次数(这样头信息仅需上传一次,减少流量也节省了资耗); 
    6) 网络缓存,对服务端返回数据缓存,设定有效时间,也可以使用第三方库如Okhttp, Volley 
    7) 断点续传,重试策略,Protocol Buffer;避免客户端轮询,使用服务器推送方式,数据采用增量更新,应用可设置仅在wifi环境下升级应用;善用缓存服务;在WIFI环境下下载文件;使用离线地图;暂时关闭同步;压缩数据

    6.事件分发机制

    (1)事件传递:

    ViewGroup接收到事件后进行事件分派(dispatchTouchEvent),如果自己需要处理事件则拦截(interceptTouchEvent返回true),调用自己的onTouchEvent进行事件处理;不处理(interceptTouchEvent返回false)则传给子view进行处理,再由子view进行分派(dispatchTouchEvent),处理/拦截;

    (2)事件处理:

    子View的onTouchEvent进行事件处理,若返回true,则消耗事件,不再继续传递;返回false则不处理,把这个事件往上一级的viewGroup进行传递,由上一级进行处理。

    (3)view的dispatchTouchEvent

    1) view之所有dispatchTouchEvent方法,因为view可以注册很多事件监听器,如onClick, onLongClick, onTouch, view自身的onTouchEvent方法,这么多事件需要管理者dispatchTouchEvent。所以view也会有事件分发。 
    2) view事件相关的方法调用顺序:onTouchListener > onTouchEvent > onLongClickListener > onClickListener

    (4)注意点:

    1) 不论view自身是否注册事件,只要view可点击就会消费事件,如view注册了onClickListener\ onLongClickListener\ onContextClickListener\ android:clickable = “true”; 
    onTouchListener返回false才会调用onClickListener 
    2) 即使给view注册了onTouchListener也不会影响view的可点击状态,只要不返回true就不会消费事件; 
    3) ViewGroup和ChildView同时注册了事件监听器,由ChildView消费; 
    4) 一次触摸流程中产生事件应被同一个view消费,全部接收或全部拒绝;

    7.消息机制

    handler消息机制,它可以将一个任务切换到handler所在的线程中去执行;handler需要MessageQueue\Looper\Message的支持;各自的任务是: 
    Handler–负责消息的发送、接收处理; 
    MessageQueue–消息队列,一个消息存储单位,经常需要进行增减,内部使用单链表结构; 
    Looper–消息循环,不停地从MessageQueue中取消息,如有新消息就会立即处理,否则一直阻塞; 
    Message–消息载体。

    (1)Handler是怎么接收到消息

    1) Looper的prepare()会为当前线程创建一个Looper实例,该实例会创建一个消息队列MessageQueue对象,将线程设为当前线程;最后将该实例保存在当前线程中; 
    2) 构建Handler时,会先获取到当前Handler所在线程的Looper并得到其中的MessageQueue; 
    2) 使用Handler发送消息时,会将一个Message保存到当前线程Looper中的MessageQueue中; 
    3) 调用loop()方法会开启消息循环,不断从MessageQueue中取消息,当收到消息后,会调用msg.target.dispatchMessage(msg);来处理消息;最终会调用Handler的handlerMessage进行处理消息;

    (2)Handler是怎么发送消息

    Handler的post一个Runnable对象和sendMessage一个Message对象

    8.view绘制原理

    view绘制到手机屏幕上需要经过三个步骤:measure(测量控件大小)、layout(view摆放位置)、draw(view的绘制)

    (1)view的测量measure

    1) 作用:测量视图大小,即视图宽高,在view中measure为final型,子类不能修改,它内部会调用onMeasure(),视图大小最终在这里确定,调用setMeasuredDimension保存计算结果; 
    2) MeasureSpec:view的测量模式MeasureSpec封装的是父容器传递给子容器的布局要求,MeasureSpec是由父view的MeasureSpec和子view的LayoutParams(定义view的layout_width\layout_height)通过计算得出子view的测量要求。 
    MeasureSpec是由一个32位整型数组成,高2位是mode,后面30位是size。 
    1) mode一共有三种模式:UNSPECIFIED:父容器对子容器没有任何限制,任意大;EXACTLY:父容器为子容器设置了尺寸,子容器应该服务这些边界;AT_MOST:子容器可以声指指定大小内的任意大小,最大不得超过指定大小。 
    2) measure会遍历整棵view树,测量每个view真实尺寸,ViewGrou向它内部的每个子view发送measure命令,子view在onMeasure()函数来测量自己的尺寸,再调用setMeasuredDimension()方法将测量结果保存至View的mMeasuredWidth和mMeasureHeight中,单位是像素。

    (2)layout

    layout的主要作用 :根据子视图的大小以及布局参数将View树放到合适的位置上。 
    ViewGroup:1)根据parent传递的位置信息,设置自己的位置;2)根据自己的layout规则,为每一个子view计算出准确的位置,并将layout流程传递给子view 
    View:根据parent传递的位置信息,设置自己的位置

    (3)draw

    根据measure, layout得到的参数将视图显示在屏幕上,子类不能修改此方法; 
    绘制步骤: 
    1)绘制背景(drawBackground) 
    2)保存canvas的layer,准备fading; 
    3)绘制view的content(onDraw方法); 
    4)绘制children(dispatchDraw方法); 
    5)绘制fading edges,再还原layer; 
    6)绘制装饰器,如scrollBar

    9.方法数超过65535的解决办法

    (1)出现原因

    1) android中单个dex文件能包含的最大方法数65535,类的数量也有这个限制,这包含android framework, 依赖的jar包及应用本身的代码中所有的方法。 
    2) 超过了LinearAlloc缓冲区大小,应用在安装时,系统会通过dexopt来优化dex文件,在优化过程中dexopt采用了一个固定大小的缓冲区来存储应用中所有的方法信息,该缓冲区就是LinearAlloc。它在新版本中是8mb或16mb,但在android2.2,2.3上只有5mb。有时方法数没超,但是存储空间超过了5mb,dexopt程序会报错,导致安装失败。

    (2)解决方案

    1) 删除无用的代码和第三方库 
    2) 利用插件来动态加载部分dex 
    3) multidex解决方案(可从apk中加载多个dex文件) 
    使用方法:build.gradle中添加multidex的依赖; 
    让自定义的Application继承MultidexApplication(在attachBaseContext方法中加入multiDex.install(this)),或是在mainfest文件的Application直接设成MultidexApplication。

    (3)multidex存在的问题

    1) 应用启动速度会降低,由于应用启动时会加载额外的dex文件,将会造成启动速度除低,还可能造成ANR,所以尽可能第二个dex不要太大; 
    2) 由于dalvik LinearAlloc的bug,这可能导致multidex的应用无法在android 4.0之前的手机上运行。

    10.binder

    (1)Android为什么要采用Binder作为IPC机制

    1)性能方面:Binder数据拷贝只需一次,而管道、消息队列、Socket都需要2次,共享内存不需要拷贝,性能解度,Binder仅次于共享内存;
    2) 稳定性方面:Binder是基于C/S架构,架构清晰,稳定性好。共享内存实现方式复杂,没有客户和服务端之别,需要充分考虑访问临界资源的并发同步问题,否则会出现死锁等问题,故Binder稳定性优于共享内存; 
    3) 安全方面:传统的IPC接收方无法获得对方进程可靠的UID/PID,无法鉴别对方身份。而Binder机制的Server端可根据权限控制策略,判断UID/PID是否满足访问权限。

    (2)实现方法

    1) 在服务端新建需要的AIDL类(声明以.aidl为后缀的接口类,并声明相应的方法),保存后会在gen目录下生成相应的java类,它是系统为我们声明的aidl接口生成的Binder类,继承自android.os.IInterface,自己也还是一个接口。 
    2) 编写服务端Service类,新建一个.Stub对象,在onBind方法中返回定义的aidl的Binder对象。 
    3) 在服务端注册服务; 
    4) 在客户端新建ServiceConnection对象,重写onServiceConnected方法和onServiceDisconnected方法,在onServiceConnected方法可以获取到服务端的Binder对象,从而可以调用服务端的方法进行通信。 
    5) 在客户端绑定service对象

    11.anr

    (1)android怎么定义应用出现ANR

    1) 应用在5秒内未响应用户的输入事件; 
    2) BroadcastReceiver未在10秒内完成相关的处理;

    (2)出现场景

    1) 主线程阻塞、挂起、死循环;应用进程的其他线程CPU占用率高,使主线程无法抢占CPU时间片; 
    2) 其他应用进程抢占CPU时间片,使当前应用无法抢占到;其他进程CPU占用率高;当前应用进程进行进程间通信请求其他进程,其他进程操作长时间没有反馈等;

    (3)从哪可以查看到引起的原因

    当前运行的程序发生ANR时,会将函数的堆栈信息输出到/data/anr/trace.txt文件中,最新的ANR信息在最开始部分; 
    后台的ANR一般不弹框,可以在开发者选项里勾选“应用程序无响应”即可对后台ANR也进行弹窗显示。

    (4)如何避免

    1) 使用AsyncTask或是Thread/HandlerThread来进行耗时操作,还可设置Thread的优先级设置成Process.THREAD_PRIORITY_BACKGROUND; 
    2) 使用Handler处理工作线程结果,而不使用Thread.wait()或Thread.sleep()来阻塞主线程; 
    3) 在onCreate和onResume回调中尽量避免耗时操作; 
    4) BoardCastReceiver的onReceive代码要尽量减少耗时,可使用IntentService处理。

    12.listview优化

    (1)每次getView执行时间最长不得超过多少否则给用户卡顿感觉

    1S内屏幕大概绘制30帧,用户才会觉得它比较流畅,每帧可用时间为33.33ms,每一屏一般要6个ListItem,加上一个重用的convertView:33.33ms/7=4.76ms,即每个getView要在4.76ms内完成工作才会较流畅。但每个getView间的调用会有一定间隔,所以留给getView使用的时间应该控制在4ms内,否则滑动ListView会有卡顿的感觉。

    (2)优化方法

    1) 使用ViewHolder+converView模式,这样避免每次在调用getView时,都重新inflate一个view,通过findViewById实例化数据; 
    2) adapter中有耗时操作,异步加载; 
    3) 为图片设置缓存;图片加载可使用第三主库如Glide, Picasso 
    4) ListView滑动时停止加载图片和分页加载; 
    5) 在adapter的getView中尽可能减少逻辑判断; 
    6) 将ListView的scrollingCache和animateCache的属性设置为false; 
    7) 尽可能减少List Item的Layout层次,如可用RelativeLayout替换LinearLaout

    13. bitmap怎么避免OOM

    (1) 加载大图时,可先对图片进行压缩

    在一个很小的ImageView上显示一张大图,是不值当的。BitmapFactory提供了多个解析方法(dcodeByteArray, decodeFile, decodeResource)用于创建Bitmap对象,它提供了一个可选的BitmapFactory.Options参数,将inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值不再是一个bitmap,而是null,但BitmapFactory.Options的outWidth, outHeight和outMineType属性都会被赋值,此时可根据图片情况进行压缩。能过设置BitmapFactory.Options中的inSampleSize值就可以实现。

    (2)使用图片缓存技术

    LrcCache来缓存图片,LruCache

    (3)选择RGB_565或是ARGB_4444的编码格式,ARGB_8888的编码格式占4个字节。

    (4)android系统怎么判断发生OOM

    在Android2.x系统: dalvik allocated + external allocated + 新分配的大小 >= getMemoryClass值时就会发生OOM 
    在Android4.x系统废除了external的计数器bitmap的分配改到dalvik的Java heap中申请,只要allocated + 新分配的内存 >= getMemoryClass()就会发生OOM;

    14. java静态内部类和内部类区别

    1) 非静态内部类会隐式持有一个外围类的引用,非静态内部类能访问外围类的一切成员,包括私有变量,外部类不能直接访问内部类的成员,但可通过内部类的实例访问; 
    在构造内部了类对象时采用:

    OuterClass.InnerClass innerObject =newOuterClass().newInnerClass();
    • 1
    • 1

    2) 静态内部类不能访问外围类的非公开成员,因为它们是两个不同的类 
    在实例化时采用:

    OuterClass.StaticNestedClass nestedObject =newOuterClass.StaticNestedClass();
    • 1
    • 1

    15. android UI性能优化

    (1) 卡顿(Jack)

    安卓设备的屏幕刷新率一般是60帧每秒,所要要渲染的内容能在16ms内完成,每丢一帧,用户就会感觉动画在跳动。

    (2) Choreographer帧率检测方案

    (1)VSync信号及作用 
    Android系统一帧绘制完成,显示器会发出一个垂直同步信息(vertical synchronization)VSync信号,显示器通常以固定频率进行刷新,这个刷新率就是VSync信号产生的频率。为解决GPU和视频控制器不同步,GPU有一个垂直同步(V-Sync)来通知界面进行渲染、绘制,每一次同步周期为16.6ms,代表一帧的刷频率,一次界面渲染会回调doFrame方法,如果两次doFrame之间的间隔大于16.6ms,说明发生了卡顿,可保存两次doFrame时间进行相减再除以刷新频率,这样算出来的结果就是两次doFrame的掉帧数。 
    (2)Choreographer怎么检测掉帧 
    Choregrapher对VSync信号做了监听,当有VSync消息的时候会执行onVsync,最终走到Choregrapher的doFrame,这里会将callback队列中取出runnable进行绘制。 
    通过Choreographer设置它的FrameCallback,在每一帧被渲染时记录下它开始渲染的时间,在下一帧渲染过程中判断是否出现掉帧。 
    (3)Android的一个显示周期可表现为以下几部分: 
    CPU+GPU绘制帧数据,绘制结束的数据存放在缓冲区BufferQueue中; 
    SurfaceFlinger从BufferQueue中取数据并计算; 
    Choreographer完成最终绘制;

    16. TCP/IP五层通信体系结构

    应用层(应用程序数据)》传输层(Segment/Datagram)传输的是TCP数据或是UDP数据 》网络层(Packet,路由) 》数据链路层(Frame,以太网交换机) 》物理层(Bit,集线器,双绞线)

  • 上一篇:剖析Android的系统架构,加强对Android编程理解和掌控

    下一篇:Android Studio导入项目非常慢的解决办法

网站导航
2001-2016 达内时代科技集团有限公司 版权所有 京ICP证8000853号-56