面试Android面试准备

中高级Android工程师面试

2018-07-18  本文已影响305人  苏苏说zz

Activity面试详情


activity生命周期

1.activity的4种状态

running/paused/stopped/killed

2.activity的生命周期

activity启动->onCreate()->onStart()->onResume()

点击home键回到主界面(activity不可见)->onPause()->stop()

当我们再次回到原activity时->onRestart()->onStart()->onResume()

退出当前activity时->onPause()->onStop()->onDestroy()

3.android进程优先级

前台/可见/服务/后台/空

二.android任务栈

三.activity启动模式

启动模式可在AndroidManifest.xml中,通过标签的android:launchMode属性设置。

1.standard模式

    a.Activity的默认启动模式

    b.每启动一个Activity就会在栈顶创建一个新的实例。例如:闹钟程序

    缺点:当Activity已经位于栈顶时,而再次启动Activity时还需要在创建一个新的实例,不能直接复用。

2.singleTop模式

    特点:该模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶直接复用,否则创建新的实例。 例如:浏览器的书签

    缺点:如果Activity并未处于栈顶位置,则可能还会创建多个实例。

3.singleTask模式

    特点:使Activity在整个应用程序中只有一个实例。每次启动Activity时系统首先检查栈中是否存在当前Activity实例,如果存在

              则直接复用,并把当前Activity之上所有实例全部出栈。例如:浏览器主界面

4.singleInstance模式

    特点:该模式的Activity会启动一个新的任务栈来管理Activity实例,并且该势力在整个系统中只有一个。无论从那个任务栈中    启动该Activity,都会是该Activity所在的任务栈转移到前台,从而使Activity显示。主要作用是为了在不同程序中共享一个Activity

四.scheme跳转协议

Android中的Scheme是一种页面内跳转协议,通过自定义Scheme协议,可以跳转到app中的任何页面。

1.服务器可以定制化跳转app页面

2.app可以通过Scheme跳转到另一个app页面

3.可以通过h5页面跳转app原生页面


fragment面试详解

一.fragment为什么会称为第五大组件

Android有四大组件,activity,broadcastReceiver,service,contentprovider。没错,可是我觉得Fragment的作用不亚于它们,因此自封为第五大组件。

二.fragment加载到activity的两种方式

1.添加fragment到activity的布局文件当中

静态启动:所谓的静态启动就是在xml文件中指定该fragment组件

2.动态在activity中添加fragment

所谓的动态启动,就是通过代码启动fragment:

三.FragmentPageAdapter和FragmentPageStateAdapter的区别

FragmentPageAdapter在每次切换页面的的时候,是将Fragment进行分离,适合页面较少的Fragment使用以保存一些内存,对系统内存不会多大影响

FragmentPageStateAdapter在每次切换页面的时候,是将Fragment进行回收,适合页面较多的Fragment使用,这样就不会消耗更多的内存

四.fragment的通信

1.在fragment调用activity方法  getActivity()

2.在activity调用fragment方法 接口回调

3.在fragment调用fragment方法 findFragmentById

五.fragment的replace,add,remove三个方法



Service面试详解

一.service是什么?

四大组件之一,service是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件

二service启动方式

1.startService

1.定义一个类继承service

2.在manifest.xml文件中配置该service

3.使用context的startService(intent)启动该service

4.不再使用时,调用stopService(Intent)停止该服务

2.bindService

1.创建bindService服务段,继承自service并在类中,创建一个实现binder接口的实例对象并提供公共方法给客户端调用

2从onbind()回调方法返回此binder实例

3在客户端中,从onserviceconnected()回调方法接收binder,并使用提供的方法调用绑定服务


BroadCast receiver面试详情

一.广播定义

在android中,broadcast是一种广泛的运用的在应用程序直接传输信息的机制,android中我们要发送的广播内容是一个intent,这个intent中可以携带我们要传送的数据

二.广播使用场景

1.同一个app具有多个进程的不同组件之间的消息通信

2.不同app之间的组件之间消息通信

三.实现广播-receiver

1.静态注册:注册完成就一直运行

2.动态注册:跟随activity的生命周期


webview面试详解

一.webview常见的一些坑

1. webview 在android api16以及之前版本的安全漏洞,该漏洞是因为程序没有正确的限制webview.addjavascriptinterface方法,让远程攻击者可以使用java的反射机制利用该漏洞执行任意的java对象方法。

2. webview动态添加到其他布局的时候,在activity销毁的生命周期时,需要主动调用webview.removeallviews和webview的ondestory方法释放内存,否则会导致内存泄漏。

3. jsbridge ,js桥可以允许远程网页端与android的native端进行通信,通俗的说就是使用js桥可以在android代码中调用网页的js方法,也可以让js调用原生的代码

4. webview.onpagefinished方法,该方法并不靠谱,更加靠谱的方法是使用onprogresschange方法代替该方法的功能,当newProgress为100的时候,即是页面加载完成。

5.webview硬件加速导致渲染问题,比如加载的时候会有闪屏现象,解决方式就是暂时关闭硬件加速。


handler面试详解

一.handlerd的工作原理

处理过程: 

从handler中获取一个消息对象,把数据封装到消息对象中,通过handler的send…方法把消息push到MessageQueue队列中。 

Looper对象会轮询MessageQueue队列,把消息对象取出。 

通过dispatchMessage分发给Handler,再回调用Handler实现的handleMessage方法处理消息。

流程图: 

Handler的实现中适及以下对象: 

1、Handler本身:负责消息的发送和处理 

2、Message:消息对象 

3、MessageQueue:消息队列(用于存放消息对象的数据结构) 

4、Looper:消息队列的处理者(用于轮询消息队列的消息对象,取出后回调handler的dispatchMessage进行消息的分发,dispatchMessage方法会回调handleMessage方法把消息传入,由Handler的实现类来处理)

Message对象的内部实现是链表,最大长度是50,用于缓存消息对象,达到重复利用消息对象的目的,以减少消息对象的创建,所以通常我们要使用obtainMessage方法来获取消息对象

安全:Handler的消息处理机制是线程安全

关系:创建Handler时会创建Looper,Looper对象的创建又创建了MessageQueue


view绘制机制

一.View结构原理

View定义了绘图的基本操作基本操作由三个函数完成:measure()、layout()、draw(),其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。具体操作如下:

1、measure操作     measure操作主要用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。measure()函数中又会调用下面的函数:     

(1)onMeasure(),视图大小的将在这里最终确定,也就是说measure只是对onMeasure的一个包装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。 

2、layout操作     layout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型,要求子类不能修改。layout()函数中有两个基本操作:     (1)setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来;     

(2)onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的; 

3、draw操作     draw操作利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法,因为其内部定义了绘图的基本操作:     

(1)绘制背景;     

(2)如果要视图显示渐变框,这里会做一些准备工作;     

(3)绘制视图本身,即调用onDraw()函数。在view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的显示(比如TextView在这里实现了绘制文字的过程)。而对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的,其包含了多个子view,而子View已经实现了自己的绘制方法,因此只需要告诉子view绘制自己就可以了,也就是下面的dispatchDraw()方法;     

(4)绘制子视图,即dispatchDraw()函数。在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法;     

(5)如果需要(应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge),开始绘制渐变框;     

(6)绘制滚动条;      从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。


事件分发机制

请谨记:Android事件分发流程 = Activity -> ViewGroup -> View

即:1个点击事件发生后,事件先传到Activity、再传到ViewGroup、最终再传到 View

从上可知,要想充分理解Android分发机制,本质上是要理解:

Activity对点击事件的分发机制

ViewGroup对点击事件的分发机制

View对点击事件的分发机制

即按顺序讲解:Activity事件分发机制、ViewGroup事件分发机制、View事件分发机制

1.Activity的事件分发机制

当一个点击事件发生时,事件最先传到Activity的dispatchTouchEvent()进行事件分发

当一个点击事件发生时,从Activity的事件分发开始(Activity.dispatchTouchEvent())

方法总结

2 ViewGroup事件的分发机制

ViewGroup事件分发机制从dispatchTouchEvent()开始

结论:Android事件分发总是先传递到ViewGroup、再传递到View

过程:当点击了某个控件时

示意图

核心方法总结

示意图

3 View事件的分发机制

View事件分发机制从dispatchTouchEvent()开始

每当控件被点击时:

示意图

注:onTouch()的执行 先于 onClick()

核心方法总结

2.4 总结


okhttp网络框架

一,get请求的使用方法

使用OKHttp进行网络请求支持两种方式,一种是同步请求,一种是异步请求

private void postDataWithParame() {

    OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。    FormBody.Builder formBody = new FormBody.Builder();//创建表单请求体    formBody.add("username","zhangsan");//传递键值对参数    Request request = new Request.Builder()//创建Request 对象。            .url("http://www.baidu.com")

            .post(formBody.build())//传递请求体            .build();

    client.newCall(request).enqueue(new Callback() {。。。});//回调方法的使用与get异步请求相同,此时略。}


retrofit网络框架

Retrofit是Square开源的一款适用于Android网络请求的框架。Retrofit底层是基于OkHttp实现的,与其他网络框架不同的是,它更多使用运行时注解的方式提供功能。

步骤1:添加Retrofit库的依赖 

1. build.gradle                                                                                                    dependencies {                                                                                                                           compile 'com.squareup.retrofit2:retrofit:2.0.2' // Retrofit库                                                 compile 'com.squareup.okhttp3:okhttp:3.1.2' // Okhttp库                                                 }
2. 添加 网络权限 AndroidManifest.xml

步骤2:创建 接收服务器返回数据 的类 

步骤3:创建 用于描述网络请求 的接口 

步骤4:创建 Retrofit 实例 

步骤5:创建 网络请求接口实例 并 配置网络请求参数 

步骤6:发送网络请求(异步 / 同步)

封装了 数据转换、线程切换的操作

步骤7: 处理服务器返回的数据


recyclerview面试详解

一.recyclerview是Android 5.0推出的,是support-v7包中的新组件。

第一步,导入support-v7包

第二步:初始化recycleview

第三步:写adapter,这里是填viewholder的,这个viewholder就是我下面写的myholder。

二.recyclerview加载卡顿

主要就是对onScrollStateChanged方法进行监听,然后通知adapter是否加载图片或复杂布局。对于复杂布局的优化效果还是很明显的。


listview优化方案

一.convertView的使用,主要优化加载布局问题

1.listivew每次滚动都会调用gitview()方法,所以优化gitview是重中之重。

二.内部类ViewHolder的使用。主要优化加载控件

主要优化getView方法中每次回调用findviewByID()方法来获取一次控件的代码。

新增加内部类ViewHolder,用于对控件的实力存储进行缓存。

convertView为空时,viewHolder会将空间的实力存放在ViewHolder里,然后用setTag方法讲viewHolder对象存储在view里。

convertView不为空时,用getTag方法获取viewHolder对象.

三.有没有想过ListView加载成千上万的数据为什么不出OOM错误?

最主要的是因为RecycleBin机制。

RecycleBin中有两个重要的View数组,分别是mActiveViews和mScrapViews。

这两个数组中所存储的View都是用来复用的,只不过mActiveViews中存储的是OnScreen的View,这些View很有可能被直接复用;而mScrapViews中存储的是OffScreen的View,这些View主要是用来间接复用的。



Android常用性能优化方案

一.布局优化

1)HTTP请求方式

这里指的是客户端与服务端交互,拿到数据、解析、再到显示到界面整个过程耗费的时间。

这个部分涉及客户端的优化,也涉及服务端的优化,这里只讨论客户端。

使用优秀的开源Http框架是我们比较好的选择,它的优点是经过市场的验证. 加快响应速度(网络请求框架)。

2)数据解析

实际开发当中服务端的返回数据格式无非就两种:

- JSON

- XML

在Android中均可以使用优秀的解析库来加快我们的解析速度,XML中有dom4j,JSON有Jackson、Gson,我们通过这些库实现我们更快的完成数据解析,提高我们的开发效率。

3)数据存储

为了提高应用程序的响应时间,数据缓存是一个比较好的方式,我们可以预处理服务器返回的数据,对数据进行缓存刷新。

- 异步请求网络数据

- 预处理服务器返回数据

- 异步进行数据存储操作

- 数据缓存刷新

- Timeout超时重试

- 在主线程中操作UI

二.界面卡顿

ANR表示”应用程序无响应”,这个是需要我们避免发生的事情,出现这个异常的原因:

- 主线程 (“事件处理线程” / “UI线程”) 在5秒内没有响应输入事件

- BroadcastReceiver在10秒内没有执行完毕

导致ANR的原因有很多,一般情况就是在UI线程做了耗时的操作,例如”网络请求”、数据库操作。

那么如何避免?

- UI线程只做界面刷新,不做任何耗时操作,耗时操作放在子线程来做

- 可以使用Thread+handle或者AsyncTask来进行逻辑处理

三.ListView和Bitmap优化

listView优化主要分为三个方面:

(1)使用ViewHolder并避免在getView方法中执行耗时操作 

(2)根据列表的滑动状态来控制任务的执行频率,比如当列表快速滑动时不适合开启大量的异步任务, 

(3)使用硬件加速来使listView的滑动更加流畅

Bitmap优化:

主要是通过BitmapFactory.Options来根据需要对图片进行采样,采样的过程主要使用到了BitmapFactory.Options 

来根据需要对图片进行采样,采样的过程主要使用到了BitmapFactory.Options的inSampleSize参数

四.线程优化

线程优化的思想是采用线程池,避免程序中存在大量的Thread。线程池可以重用内部的线程,从而避免了线程的创建和销毁带来的性能开销,同时线程池可以有效的控制线程的最大并发数,避免了大量线程因互相抢占系统资源而导致阻塞现象的发生。因此在实际开发中应尽量采用线程池,而不是每次都要创建一个Thread对象。

五.代码优化

 对常量使用static修饰符

- 使用静态方法

- 减少不必要的成员变量

- 尽量不要使用枚举,少用迭代器

- 对Cursor、Receiver、Sensor、File等对象,要注意它们的创建、回收与注册、反注册

- 避免大量使用注解、反射

- 使用RenderScript、OpenGL来进行复杂的绘图操作

- 使用SurfaceView来替代View进行大量、频繁的绘图操作

- 尽量使用视图缓存,而不是每次都执行inflate()方法解析视图

上一篇 下一篇

猜你喜欢

热点阅读