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
新的方案回答
方案一, handler方案
activity向fragment传递消息
activity响应事件,发送msg,到fragment中,而fragment中用来接收msg,所以用注册Handler对象,activity中发送msg的对象与fragment中handler对象必须为同一个(handler,msgqueen和looper相互唯一绑定),所以要在activity中暴露pubilic方法让fragment的acttch周期中传递handler
方案二,利用广播的方式
在fragment中发送广播,在activity中注册广播接收者
方案三、使用EventBus3.0通信*
EventBus是一款针对Android优化的发布/订阅事件总线
方案四,使用接口’
在fragment中创建接口,activity实现接口中方法,完成回调和参数传递。
总结:
如果项目中fragment不是很多话,可以用广播传递,注意广播的注销,也比较简单。
最后不要使用Handler,耦合比较高,处理不好容易内存泄露,无法获取activity返回值
EventBus采用反射机制,造成性能上问题,无法获取activity的返回值
普通接口,用于少量fragment中,性能还不错,怕扩展。
五.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需要加载各种各样的网页并且需要在页面加载完成时采取一些操作的话,可以在WebChromeClient.onProgressChanged()中处理原本用WebViewClient.onPageFinished()执行的操作
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()方法解析视图
Android中常见的设计模式
设计模式有23种 说说几种常见的设计模式
1.单例模式:
单例模式太多了,在整个应用中只有一个,标准的单例模式写法:
2.Builder模式
常见的builder模式有创建dialog的过程。
3.策略方法模式
比如在注册一个用户信息时,可能最终会注册到不同的服务器上,但是对于上层代码并不关心最终用户数据到哪,只需要有地方存储就可以,所以可以抽象出存储函数,真正的实现让其实现的子类去做。
4.工厂方法模式
我们创建的activity或者fragment中,定义基类的时候,可以将每个界面不同的地方抽象出来,让真正实现的子类去实现该统一的方法。
5.观察者模式
在安卓中观察者模式用的比较多的地方在数据库变化或者listview内容有变化时,使用notifyDataSetChanged()方法。
6.组合模式
这种模式在安卓中最常见,Android中的view是一种树形结构,每个viewGroup包含一些列的view,而每个viewGroup本身又可以当做一个view,所以最终手机上呈现出来的界面,是由一个个view组合而成的。
7.适配模式
其实适配器模式很容易理解,我们在Android开发时也经常用到。比较典型的有ListView和RecyclerView。为什么ListView需要使用适配器呢?主要是,ListView只关心它的每个ItemView,而不关心这个ItemView具体显示的是什么。而我们的数据源存放的是要显示的内容,它保存了每一个ItemView要显示的内容。ListView和数据源之间没有任何关系,这时候,需要通过适配器,适配器提供getView方法给ListView使用,每次ListView只需提供位置信息给getView函数,然后getView函数根据位置信息向数据源获取对应的数据,根据数据返回不同的View。
8.模板方法模式
这种模式也相当常见,比如我们的activity或者fragment,在base中定义了一些列的周期函数,基本把整个activity的框架全部定义好了,所以我们只需要进程基类的activity或者fragment方法,然后在定义好的周期函数中实现我们需要的内容就可以,而不用关心整个activity的启动所有过程。
9.代理模式
定义:为其他类提供一种代理以控制这个对象的访问。
在安卓中进程通信是一个很常见的东西,如果需要进行进程通信则可以通过使用AIDL来获取远程service的代理,然后我们可以通过这个代理来执行响应的操作。
java的三大特性
java有三大特性:封装,继承和多态。
一.封装
1. 封装就是将类的信息隐藏在类内部,不允许外部程序直接访问,而是通过该类的方法实现对隐藏信息的操作和访问。
2. 封装是怎么实现的呢?
a. 需要修改属性的访问控制符(修改为private);
b. 创建getter/setter方法(用于属性的读写);
c. 在getter/setter方法中加入属性控制语句(用于判断属性值的合法性);
二.继承
继承是类与类的一种关系,在Java中是单继承的,也就是说一个子类只有一个父类。
三.多态
多态指的是对象的多种形态。多态有两种:引用多态和方法多态。继承是多态的实现基础。
1.引用多态
父类的引用可以指向本类的对象;父类的引用可以指向子类的对象。
2. 方法多态
创建父类对象时,调用的方法为父类方法;
创建子类对象时,调用的方法是子类重写的方法或继承自父类的方法;
注意:不允许通过父类的引用调用子类独有的方法。
EventBus的基本用法
我需要在一个Activity里注册EventBus事件,然后定义接收方法,这跟Android里的广播机制很像,你需要首先注册广播,然后需要编写内部类,实现接收广播,然后操作UI。所以,在EventBus中,你同样得这么做。
Android三大图片加载框架
一.ImageLoader框架
是很早开源的图片缓存,在早期被很多应用使用
1.多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
2.支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
3.支持图片的内存缓存,文件系统缓存或者SD卡缓存
4.支持图片下载过程的监听
5.根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
6.较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片
7.提供在较慢的网络下对图片进行加载
8. 默认实现多种内存缓存算法这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。
设计原理
二、Picasso介绍
picasso是Square公司开源的一个Android图形缓存库,可以实现图片下载和缓存功能
Picasso不仅实现了图片异步加载的功能,还解决了android中加载图片时需要解决的一些常见问题:
1.在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题。
2.使用复杂的图片压缩转换来尽可能的减少内存消耗
3.自带内存和硬盘二级缓存功能
三、Glide简介
Glide是一个高效、开源、Android设备上的媒体管理框架,Glide具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个,一个是实现平滑的图片列表滚动效果(滚动流畅),另一个是支持远程图片的获取、大小调整和展示
Toolbar面试详解
今天面试问我Toolbar是什么,当时我一脸懵逼,毕竟之前都是自定义导航,后来网上了解了一下
Toolbar是什么
Toolbar是Google在Android 5.0中推出的一款替代ActionBar的View。ActionBar必须得作为Activity内容的一部分,而Toolbar可以放在任何层次。Toolbar比ActionBar支持更多的功能,从开始到终点,Toolbar包含下面可选的元素:
- 一个导航按钮。 可以是一个向前的按钮、导航菜单按钮,等等。
- 一个logo图片
- 标题和副标题
- 一个或多个自定义一View
- 一个menu
mvc mvp mvvm区别
MVC模式:
1. MVC的所有通信都是单向的。
2. view传送指令到controller(用户也可以直接将指令传到controller)。
3. controller完成业务逻辑后要求model改变状态。
4. model将新的数据发送到view,用户得到反馈。
MVP模式:
MVP模式将Controller改名为Presenter,同时改变了通信方向。
1. 各部分之间的通信都是双向的。
2. View与Model不发生联系,都通过Presenter传递
3. View非常薄,不部署任何业务逻辑,称为“被动视图”,即没有任何主动性,而Presenter非常厚,所有逻辑都部署在这里。
MVVM模式:
MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。
唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。Angular 和 Ember 都采用这种模式