###Android面试总结(持续更新修改)
1.Android 的四大组件是哪些,它们的作用?
①Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很多持久化的事情,妥善管理生命周期以及一些跳转逻辑
②service:后台服务于 Activity,封装一个完整的功能逻辑实现,接受上层指令,完成相关的事物
③Content Provider:是 Android 提供的第三方应用数据的访问方案,可以派生 Content Provider 类,对外提供数据,可以像数据库一样进行选择排序,屏蔽内部数据的存储细节,向外提供统一的接口模型,大大简化上层应用,对数据的整合提供了更方便的途径
④BroadCastReceiver:接受一种或者多种Intent作触发事件,接受相关消息,做一些简单处理,转换成一条Notification,统一了 Android 的事件广播模型
2.Activity的生命周期,及每个周期的应用场景
比如说手机卫士每次进入某个界面的时候都要看到最新的数据,这个刷新列表的操作 就放在onStart()的方法里面.这样保证每次用户看到的数据都是最新的.
多媒体播放, 播放来电话.
onStop() 视频,
视频声音设置为0 , 记录视频播放的位置 mediaplayer.pause();
onStart() 根据保存的状态恢复现场. mediaplayer.start()
3.Activity的四种启动模式分别是什么,以及他们的特点
意义在于 : 记录这些activity开启的先后顺序,google引入任务栈(task stack)概念,帮助维护好的用户体验。
①standard 默认标准的启动模式, 每次startActivity都是创建一个新的activity的实例。
适用于绝大大数情况
②singleTop 单一顶部,如果要开启的activity在任务栈的顶部已经存在,就不会创建新的实例,而是调用 onNewIntent() 方法。应用场景: 浏览器书签。 避免栈顶的activity被重复的创建,解决用户体验问题。
③singletask 单一任务栈 ,activity只会在任务栈里面存在一个实例。如果要激活的activity,在任务栈里面已经存在,就不会创建新的activity,而是复用这个已经存在的activity,调用 onNewIntent() 方法,并且清空这个activity任务栈上面所有的activity 应用场景:浏览器activity, 整个任务栈只有一个实例,节约内存和cpu的目的注意: activity还是运行在当前应用程序的任务栈里面的。不会创建新的任务栈。
④singleInstance 单态 单例模式单一实例,整个手机操作系统里面只有一个实例存在。不同的应用去打开这个activity共享 公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。
5.你后台的Activity被系统 回收怎么办?
答:重写onSaveInstanceState()方法,在此方法中保存需要保存的数据,该方法将会在activity被回收之前调用。通过重写 onRestoreInstanceState()方法可以从中提取保存好的数据
6.Fragment生命周期是什么?
onAttach() – onCreate() – onCreateView()- onActivitCreated – onStart() – onResume() – onPause()
onStop() – onDestoryView() – onDestory() – onDetach()
7.Activity和Fragment如何进行通信,Activity之间通信有几种方式
①Activity向Fragment传递数据 :
一 通过bundle设置参数Bundle bundle = new Bundle();bundle.putString(“name”,“加多宝”);sf.setArguments(bundle);
二 通过调用接口设置接口 让被接收数据方 实现该方法让发送方调用该接口
②Fragment 向 A ctivity 传递数据 :
一 通过 getActivity 强转成 需要接收数据的Activity 调用其方法 ;
二 通过接口 还可以利用 sp sqLite 等
③Activity之间传递数据:通过全局application类共享数据;通过Intent传值;使用静态变量传递数据;使用剪切板传递数据;
8.Service 的生命周期(两种)?
①onCreate – onStartCommand(每次开启都要执行,可以执行多次) – onDestory()-------只要不执行方法onStop(),在内存中永远驻留
②onCreate – onBind(只能执行一次) – onUnbind() – onDestory()-------依赖于Activity,随着Activity的销毁而关闭
注意:同一个服务可以被开启多次,但是关闭只需要一次
9.如何开机就启服务?
通过广播接收者监听开机广播然后在onReceive(Context context, Intent intent)方法 里开启相应的服务
10.Service是否在mainThread中执行, service里面是否能执行耗时的操作?
是 不能
11.Service和IntentService的区别?
Service主要用于后台服务,当应用程序被挂到后台的时候,为了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不 是独立的线程,它是依赖于应用程序的主线程的,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行耗时操作
12.广播的两种注册方式?
①清单文件注册
②代码注册
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
filter.addAction(Intent.ACTION_MEDIA_EJECT);
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addDataScheme(“file”);
sdcardStateReceiver = new SdcardStateChanageReceiver();
registerReceiver(sdcardStateReceiver,filter);
13.IPC(Inter-Progress-Communication)哪些方式?简述AIDL
Messenger Socket AIDL ContentProvider Intent
14.数据存储几种方式?分别是什么?
Android 提供了 5 种方式存储数据:
①使用 SharedPreferences 存储数据:它是 Android 提供的用来存储一些简单配置信息的一种机制,采用了 XML 格式将数据存储到设备中。只能在同一个包内使用,不能在不同的包之间使用。
②文件存储数据:文件存储方式是一种较常用的方法,在 Android 中读取/写入文件的方法,与 Java 中实现 I/O 的程序是完全一样的,提供了 openFileInput()和
openFileOutput()方法来读取设备上的文件。
③SQLite 数据库存储数据:SQLite 是 Android 所带的一个标准的数据库,它支持SQL 语句,它是一个轻量级的嵌入式数据库。
④使用 ContentProvider 存储数据:主要用于应用程序之间进行数据交换,从而能够让其他的应用保存或读取此 Content Provider 的各种数据类型
⑤网络存储数据:通过网络上提供给我们的存储空间来上传(存储)和下载(获取)我们存储在网络空间中的数据信息。
15.listView的优化
①第一层: 复用converterView
if(converterView==null) {
converterView = View.inflate(R.layout.xxx); 10–>11
}
问题: 每次执行getView()都需要执行converterView.findViewById()得到子View
②第二层: 使用ViewHolder, 减少findViewById()的次数
③第三层: 对数据列表进行分页加载显示
1). 自己做: 通过Scroll监听listView.setonScrollListener(scrollListener), 当到达底部时加载下一页列表数据并显示
2). 使用第方开源框架: Android-PullToRefresh或其它
④第四层优化: 图片级缓存处理 参见图片级缓存机制
⑤Item布局,层级越少越好,使用hierarchyview工具查看优化。
⑥item中图片时,异步加载
⑦快速滑动时,不加载图片、
⑧item中图片时,应对图片进行适当压缩
16.简述三级缓存的实现?
例如: 如何根据url根据图片显示?
①根据url从一级缓存(Map
②如果没, 根据url中包含图片名称(文件名), 手机的sd卡或内部找对就图片文件加载成bitmap如果找到了, 显示并保存到一级缓存
③ 如果没, 显示一个默认的图片, 根据url联网请求获取bitmap如果没, 显示一张代表错误的图片 如:
a. 保存到一级缓存 b. 保存到二级缓存 c. 显示图片
17.简述Handler运行原理
andriod提供了 Handler 和 Looper 来满足线程间的通信。Handler 先进先出原则。
Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。
1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列)。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到Message Queue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。
4)线程:UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。
总结:默认主线程中维护了一个Looper,而Looper中维护了MessageQueue消息池。Looper通过死循环一直检测消息池是否有消息进来,如果有则交给Handler处理。而Handler就是当时发送消息进来的对象
18.AsycTask主要用到哪些方法?他们分别运行在哪个线程?
onPreExecute()在主线程中执行异步开始前调用做一些准备工作
doInBackground(Params…params)分线程,…可以通过publishProgress来更新任务
onProgressUpdate(Progress…values)主线程中执行后台任务
onPostExecute(Result result) 主,异步任务执行之后
onCancelled 主当异步任务取消的时候会被调用这个时候onPostExecute(将不再被调用)
19.图片的加载与优化(还可以说颜色值的更改 三级缓存等)
把整张图片加载到内存中还是加载一个压缩版的图片到内存中。以下几个因素是我们需要考虑的:
• 预估一下加载整张图片所需占用的内存。
• 为了加载这一张图片你所愿意提供多少内存。
• 用于展示这张图片的控件的实际大小。
• 当前设备的屏幕尺寸和分辨率。
1 每个应用程序最高可用内存是多少。
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
2 在展示高分辨率图片的时候,最好先将图片进行压缩。压缩后的图片大小应该和用来展示它的控件大小相近,在一个很小的ImageView上显示一张超大的图片不会带来任何视觉上的好处,但却会占用我们相当多宝贵的内存,而且在性能上还可能会带来负面影响。
3 BitmapFactory这个类提供了多个解析方法(decodeByteArray, decodeFile, decodeResource等)用于创建Bitmap对象,我们应该根据图片的来源择合适的方法。
比如SD卡中的图片可以使用decodeFile方法,网络上的图片可以使用decodeStream方法,资源文件中的图片可以使用decodeResource方法。这些方法会尝试为已经构建的bitmap分配内存,这时就会很容易导致OOM出现。
4 为此每一种解析方法都提供了一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。
5 更改采样率
20.Android中常用的五种布局分别是什么?
LinearLayout线性布局;AbsoluteLayout绝对布局;TableLayout表格布局;RelativeLayout相对布局;FrameLayout帧布局
21.dp,px,sp区别及使用场景
①px (pixels)(像素:屏幕上的点 ,与密度相关。密度大了,单位面积上的px会比较多。
②dip或dp(与密度无关的像素。一种基于屏幕密度的抽象单位。设置一些view的宽高可以用这个,一般情况下,在不同分辨率,都不会有缩放的感觉。
③sp(与刻度无关的像素放大像素– 主要处理字体的大小。
22.gravity和layout_gravity的区别
android:gravity 属性是对该view中内容的限定.比如一个button 上面的text. 你可以设置该text 相对于view的靠左,靠右等位置.也可以在父布局控制所有子布局的位置
android:layout_gravity是用来设置该view相对与父view 的位置.比如一个button 在linearlayout里,你想把该button放在linearlayout里靠左靠右等位置就可以通过该属性设置
23.Padding和Margin什么区别
Padding 文字对边框, margin是控件对父窗体.Margin:一个控件与另一个控件之间的间距
Padding:一个控件的内容与边框之间间距
24.自定义view的流程(常用的方法以及作用)
继承View完全自定义或继承View的派生子类 定义自定义属性
获取自定义属性 添加属性和事件 自定义测量 重写onMesure
系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:
重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
自定义绘制
绘制自定义视图里最重要的一步是重写onDraw()方法. onDraw()的参数是视图可以用来绘制自己的Canvas对象. Canvas定义用来绘制文本、线条、位图和其他图像单元. 你可以在onDraw()里使用这些方法创建你的自定义用户界面(UI).
android.graphics框架把绘图分成了两部分:
l 画什么, 由Canvas处理
l 怎么画, 由Paint处理
例如, Canvas提供画线条的方法, 而Paint提供定义线条颜色的方法. Canvas提供画矩形的方法, 而Paint定义是否用颜色填充矩形或让它为空. 简而言之, Canvas定义你可以在屏幕上画的形状, 而Paint为你画的每个形状定义颜色、样式、字体等等.
onDraw()不提供3d图形api的支持。如果你需要3d图形支持,必须继承SurfaceView而不是View,并且通过单独的线程画图。
降低刷新频率
为了提高view的运行速度,减少来自于频繁调用的程序的不必要的代码。从onDraw()方法开始调用,这会给你带来最好的回报。特别地,在onDraw()方法中你应该减少冗余代码,冗余代码会带来使你view不连贯的垃圾回收。初始化的冗余对象,或者动画之间的,在动画运行时,永远都不会有所贡献。
加之为了使onDraw()方法更有依赖性,你应该尽可能的不要频繁的调用它。大部分时候调用 onDraw()方法就是调用invalidate()的结果,所以减少不必要的调用invalidate()方法。有可能的,调用四种参数不同类型的invalidate(),而不是调用无参的版本。无参变量需要刷新整个view,而四种参数类型的变量只需刷新指定部分的view.这种高效的调用更加接近需求,也能减少落在矩形屏幕外的不必 要刷新的页面。
25.View中的RequestLayout()和invalidate()区别?Invaldate()和postInvalidate()区别?
requestLayout:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view重新调用他的onMeasure onLayout来对重新设置自己位置。
特别的当view的layoutparameter发生改变,并且它的值还没能应用到view上,这时候适合调用这个方法。
invalidate:View本身调用迫使view重画。是在UI线程自身使用。
postInvalidate:是在非UI线程使用。
26.SufaceView和View的区别?
surfaceView是在一个新起的单独线程中可以重新绘制画面,
而View必须在UI的主线程中更新画面。
那么在UI的主线程中更新画面,那么你的主UI线程会被你正在画的函数阻塞。当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
27.简述事件分发
http://www.cnblogs.com/linjzong/p/4191891.html
28.recycleView分类型使用哪个方法?
public int getItemViewType(int position);
27.H5和WebView如何实现交互?
①如果向h5里传数据:
首先设置settings.setJavaScriptEnabled(true);
wv.loadUrl(“javascript:javacalljswithargs(” + name + “)”);
②如果让h5调用java方法:
也必须先设置settings.setJavaScriptEnabled(true);
wv.addJavascriptInterface(this, “wst”);
把自身传给h5然后调用相应的方法即可
Java方法上要加注解@JavascriptInterface
28.如何实现图文混排?
①Html.fromHtml(sb.toString(),imageGetter , null)
②SpannableStrinbBuilder
29.Android的5.0,6.0,7.0的新特性哪些?
①5.0
采用了 Google 最新推行的 Material Design 设计语言 比如RecyleView控件等 加入了阴影
锁屏通知
多用户设备共享相关功能 (类似windows的多用户)
支持 64 位 ARM、X86 和 MIPS 架构 SoC 的 Android 操作系统。
迁移数据的功能
拍照图片保存RAW格式
重启保留后台应用
②6.0(HTTP PDF)
App Permissions(软件权限管理)
Chrome Custom Tabs(网页体验提升)
Android Pay(安卓支付)
Fingerprint Support(指纹支持)
去除httpClient
USB Type-C端口支持
DataBinding 数据绑定
③7.0
安卓7.0加入了全新的API,支持第三方应用通知的快捷操作和回复,例如来电会以横幅方式在屏幕顶部出现,提供接听/挂断两个按钮;信息/社交类应用通知,还可以直接打开键盘,在输入栏里进行快捷回复。
流量保护模式
安卓7.0新增的流量保护模式不仅可以禁止应用在后台使用流量,还会进一步减少该应用在前台时的流量使用。其具体实现原理目前尚不清楚,推测其有可能使用了类似Chrome浏览器的数据压缩技术。
谷歌还扩展了ConnectivityManager API的能力,使得应用可以检测系统是否开启了流量保护模式,或者检测自己是否在白名单中。安卓7.0允许用户单独针对每个应用,选择是否开启数据保护模式
超快应用安装速度
安卓7.0中采用了一项具有实时代码剖析功能的ARI JIT编译器,它能够在安卓应用程序在运行时不断提高自身的性能,其带来的另一项优势就是能够为应用安装引入一种新的“快速通道”(quick path),能够大大加快应用安装和系统更新的速度,即便是那些大型的应用程序如游戏,在安卓6.0中需要几分钟时间才能安装和优化完成的,在安卓7.0中仅仅需要几秒钟就可以搞定。同时,因为省去了一些优化步骤,安卓7.0的系统更新速度也会大大提升。
Android N正式支持Vulkan API,包括其全部特性,尤其是能够大大降低CPU系统开销,提升描绘指令(Draw Call),当然也支持预编译着色器,这对于应用、游戏开发无疑是个大好消息。
安全方面,Android N将会支持基于文件的加密、媒体框架硬化、无缝升级,特别是最后一点,Android N会使用两个系统镜像来确保OTA更新顺利、安全。
④8.0
通知渠道 — Notification Channels
通知渠道是由应用自行定义的通知内容类别,借助渠道,开发者可以让用户对不同种类的通知进行精细控制,用户可以单独拦截或更改每个渠道的行为,而不是统一管理应用的所有通知。
画中画模式 — PIP
Android O 现已支持 Activity 的画中画模式。PIP 是一种多窗口显示模式,多用于视频播放,即你可以一边发微信一边看视频。
自适应图标 — Adaptive Icons
固定快捷方式和小部件 — Pinning shortcuts
30.这是一张数据库表(表名user 字段(id,name任意插入一条数据和修改id为1的姓名为美女?
Insert into user(id,name) values(1,”zhangsan”)
update table user set username =”美女” where id=1
31.什么是ANR?如何避免它?
①什么事ANR?
在android上,如果你的应用程序有一段时间响应不移灵敏,系统会向用户提示“应用程序无响应”(ANR:application Not Responding)对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。
分类:
KeyDispatchTimeout(5 seconds) --主要是类型按键或触摸事件在特定时间内无响应
BroadcastTimeout(10 seconds) --BroadcastReceiver在特定时间内无法处理完成
ServiceTimeout(20 secends) --小概率事件 Service在特定的时间内无法处理完成
②如何避免:
UI线程尽量只做跟UI相关的工作
耗时的操作(比如数据库操作,I/O,连接网络或者别的有可能阻塞UI线程的操作)把它放在单独的线程处理
尽量用Handler来处理UIThread和别的Thread之间的交互
32.Anadroid动画一共有几种?他们的区别是什么?
①补间动画(Tween):这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化
②帧动画(Frame):传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影
③属性动画():属性动画可以对任意对象的属性做修改
33.Android中哪些情况会导致内存泄漏和内存溢出?
①加载大图片时会内存溢出
②Android应用内存泄漏的的原因有以下几个:(abrcc)
查询数据库后没有关闭游标cursor
构造Adapter时,没有使用 convertView 重用
Bitmap对象不在使用时调用recycle()释放内存
对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放
注册没取消造成的内存泄漏
34.说说MVC和MVP的原理和他们的区别?
01.Model
Model层代表了描述业务逻辑和数据的一系列类的集合。它也定义了数据修改和操作的业务规则。
02.View
View代表了UI组件他只负责展示从Presenter接收到的数据。也就是把模型(译者注:非Modle层模型)转化成UI。
03.Presenter
Presenter负责处理View背后所有的UI事件。它通过View接收用户输入,之后利用Model来处理用户的数据,最后把结果返回给View。与View和Controller不同,View和Presenter之间是完全解耦的,他们通过接口来交互。另外,presenter不像controller处理进入的请求。
这个模式被普遍的引用于ASP.NET Web Forms 应用程序。并且也应用于windows form。
MVC即Model-VIew-Controller。他是1970年代被引入到软件设计大众的。MVC模式致力于关注点的切分,这意味着model和controller的逻辑是不与用户界面(View)挂钩的。因此,维护和测试程序变得更加简单容易。
MVC设计模式将应用程序分离为3个主要的方面:Model,View和Controller
01.Model
Model代表了描述业务路逻辑,业务模型、数据操作、数据模型的一系列类的集合。这层也定义了数据修改和操作的业务规则。
02.View
View代表了UI组件。他只负责展示从controller接收到的数据。也就是把model转化成UI。
03.Controller
Controll负责处理流入的请求。它通过View来接受用户的输入,之后利用Model来处理用户的数据,最后把结果返回给View。Controll就是View和Model之间的一个协调者。
其实最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的。
35.如何优化APK
1、代码
(1保持良好的编程习惯,不要重复或者不用的代码
(2谨慎添加libs,移除使用不到的libs。
(3使用proguard混淆代码,它会对不用的代码做优化,并且混淆后也能够减少安装包的大小。
(4native code的部分,大多数情况下只需要支持armabi与x86的架构即可。如果非必须,可以考虑拿掉x86的部分。
2、资源
(1使用Lint工具查找没有使用到的资源。去除不使用的图片,String,XML等等。
(2assets目录下的资源请确保没有用不上的文件。
(3生成APK的时候,aapt工具本身会对png做优化,但是在此之前还可以使用其他工具如tinypng对图片进行进一步的压缩预处理。
(4jpg还是png,根据需要做选择,在某些时候jpg可以减少图片的体积。
(5对于9.png的图片,可拉伸区域尽量切小,另外可以通过使用9.png拉伸达到大图效果的时候尽量不要使用整张大图。
3、策略
(1择性的提供hdpi,xhdpi,xxhdpi的图片资源。建议优先提供xhdpi的图片,对于mdpi,ldpi与xxxhdpi根据需要提供有差异的部分即可。
(2尽可能的重用已的图片资源。例如对称的图片,只需要提供一张,另外一张图片可以通过代码旋转的方式实现。
(3能用代码绘制实现的功能,尽量不要使用大量的图片。例如减少使用多张图片组成animate-list的AnimationDrawable,这种方式提供了多张图片很占空间。
4、图片优化 : https://tinypng.com/
(1tinypng是一个支持压缩png和jpg图片格式的网站,通过其独特的算法(通过一种叫“量化”的技术,把原本png文件的24位真彩色压缩为8位的索引演示,是一种矢量压缩方法,把颜色值用数值123等代替。)可以实现在无损压缩的情况下图片文件大小缩小到原来的30%-50%。
(2需要说明的是:tinypng支持png和jpg图片的压缩,并且也支持9图的压缩。
(3tinypng的缺点是在压缩某些带有过渡效果(带alpha值)的图片时,图片会失真,这种图片可以将png图片转换为下面介绍的webP格式,可以在保证图片质量的前提下大幅缩小图片的大小。
5、使用webP图片格式:https://developers.google.com/speed/webp/
(1WebP是谷歌研发出来的一种图片数据格式,它是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。根据 Google 的测试,无损压缩后的 WebP 比 PNG 文件少了 45% 的文件大小,即使这些 PNG 文件经过其他压缩工具压缩之后,WebP 还是可以减少 28% 的文件大小。目前很多公司已经将webP技术运用到Android APP中,比如FaceBook、腾讯、淘宝。webP相比于png最明显的问题是加载稍慢,不过现在的智能设备硬件配置越来越高,这都不是事儿。
(2假如你打算在 App 中使用 WebP,除了 Android4.0 以上提供的原生支持外,其他版本以可以使用官方提供的解析库webp-android-backport编译成so使用。
(3通常UI提供的图片都是png或者jpg格式,我们可以通过智图或者isparta将其它格式的图片转换成webP格式,isparta可实现批量转换,墙裂推荐!
6、使用tintcolor实现按钮反选效果:
通常钮的正反旋图片我们都是通过提供一张按钮正常图片和一张按钮反选图片,然后通过selector实现,两张图片除了alpha值不一样外其它的内容都是重复的,在Android 5.0及以上的版本可以通过tintcolor实现只提供一张按钮的图片,在程序中实现按钮反选效果,前提是图片的内容一样,只是正反选按钮的颜色不一样。
37.项目中你都用到了哪种加密方式?是如何使用的?
对称加密 非对称加密 base64 md5
38.简述HTTP 请求头都哪些?代表什么意思?如何发送数据到服务器?
39.如何优化WebView?
WebView缓存
资源文件本地存储
先加载网页后加载图片
加快HTML网页装载完成的速度
自定义出错界面
是否存在滚动条
远程网页需访问本地资源
ViewPager里非首屏WebView点击事件不响应
WebView硬件加速导致页面渲染闪烁
避免addJavaScriptInterface带来的安全问题
关于web页面如何通知WebView
WebView缓存
开启WebView的缓存功能可以减少对服务器资源的请求,一般使用默认缓存策略就可以了。
//设置 缓存模式
w
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
// 开启 DOM storage API 功能
w
webView.getSettings().setDomStorageEnabled(true);
资源文件本地存储
资源等文件(不需要更新)本地存储,在需要的时候直接从本地获取。哪些资源需要我们去存储在本地呢,当然是一些不会被更新的资源,例如图片文件,js文件,css文件,替换的方法也很简单,重写WebView的方法即可。
{
try {
if (url.endsWith("icon.png")) {
InputStream is = appRm.getInputStream(R.drawable.icon);
WebResourceResponse response = new WebResourceResponse("image/png",
"utf-8", is);
return response;
} else if (url.endsWith("jquery.min.js")) {
InputStream is = appRm.getInputStream(R.raw.jquery_min_js);
WebResourceResponse response = new WebResourceResponse("text/javascript",
"utf-8", is);
return response;
}
} catch (IOException e) {
e.printStackTrace();
}
return super.shouldInterceptRequest(view, url);
}
}
appRm为app资源管理器,读取drawable,assets,raw下的资源,都是android系统的一些很简单的函数调用。
getInputStream的参数代表资源具体位置
WebResourceResponse后的资源类型需要写正确
先加载网页后加载图片
首先阻塞网络图片的加载
mContentWV.getSettings().setBlockNetworkImage(true);
然后在网页加载完毕时加载图片
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
hideLoading();
if (!isError) {
view.setVisibility(View.VISIBLE);
mContentWV.getSettings().setBlockNetworkImage(false);
if (!mContentWV.getSettings().getLoadsImagesAutomatically()) {
mContentWV.getSettings().setLoadsImagesAutomatically(true);
}
}
}
加快HTML网页装载完成的速度
默 认情况html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但如果在这之前也有解析到image节点,那势必也会发起网络请求下载相应的图片。在网络情况较差的情况下,过多的网络请求就会造成带宽紧张,影响到css 或js文件加载完成的时间,造成页面空白loading过久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加 载。
故在WebView初始化时设置如下代码:
public void int () {
if(Build.VERSION.SDK_INT >= 19) {
webView.getSettings().setLoadsImagesAutomatically(true);
} else {
webView.getSettings().setLoadsImagesAutomatically(false);
}
}
同时在WebView的WebViewClient实例中的onPageFinished()方法添加如下代码:
@Override
public void onPageFinished(WebView view, String url) {
if(!webView.getSettings().getLoadsImagesAutomatically()) {
webView.getSettings().setLoadsImagesAutomatically(true);
}
}
从上面的代码,可以看出我们对系统API在19以上的版本作了兼容。因为4.4以上系统在onPageFinished时再恢复图片加载时,如果存在多张图片引用的是相同的src时,会只有一个image标签得到加载,因而对于这样的系统我们就先直接加载。
自定义出错界面
当WebView加载页面出错时(一般为404 NOT FOUND),安卓WebView会默认显示一个卖萌的出错界面。但我们怎么能让用户发现原来我使用的是网页应用呢,我们期望的是用户在网页上得到是如原生般应用的体验,那就先要从干掉这个默认出错页面开始。当WebView加载出错时,我们会在WebViewClient实例中的onReceivedError()方法接收到错误,我们就在这里做些手脚:
@Override
public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
loadDataWithBaseURL(null, “”, “text/html”, “utf-8”, null);
mErrorFrame.setVisibility(View.VISIBLE);
}
从上面可以看出,我们先使用loadDataWithBaseURL清除掉默认错误页内容,再让我们自定义的View得到显示(mErrorFrame为蒙在WebView之上的一个LinearLayout布局,默认为View.GONE)。
当我们做类似上拉加载下一页这样的功能的时候,页面初始的时候需要知道当前WebView是否存在纵向滚动条,如果有则不加载下一页,如果没有则加载下一页直到其出现纵向滚动条。首先继承WebView类,在子类添加下面的代码:
public boolean existVerticalScrollbar () {
return computeVerticalScrollRange() > computeVerticalScrollExtent();
}
computeVerticalScrollRange得到的是可滑动的最大高度,computeVerticalScrollExtent得到的是滚动把手自身的高,当不存在滚动条时,两者的值是相等的。当有滚动条时前者一定是大于后者的。
是否已滚动到页面底部
同样我们在做上拉加载下一页这样的功能时,也需要知道当前页面滚动条所处的状态,如果快到底部,则要发起网络请求数据更新网页。同样继承WebView类,在子类覆盖onScrollChanged方法,具体如下:
@Override
protected void onScrollChanged(int newX, int newY, int oldX, int oldY) {
super.onScrollChanged(newX, newY, oldX, oldY);
if (newY != oldY) {
float contentHeight = getContentHeight() * getScale();
// 当前内容高度下从未触发过, 浏览器存在滚动条且滑动到将抵底部位置
if (mCurrContentHeight != contentHeight && newY > 0 && contentHeight <= newY + getHeight() + mThreshold) {
// TODO Something…
mCurrContentHeight = contentHeight;
}
}
}
上面mCurrContentHeight用于记录上次触发时的网页高度,用来防止在网页总高度未发生变化而目标区域发生连续滚动时会多次触发TODO,mThreshold是一个阈值,当页面底部距离滚动条底部的高度差<=这个值时会触发TODO。
远程网页需访问本地资源
当我们在WebView中加载出从web服务器上拿取的内容时,是无法访问本地资源的,如assets目录下的图片资源,因为这样的行为属于跨域行为(Cross-Domain),而WebView是禁止的。解决这个问题的方案是把html内容先下载到本地,然后使用loadDataWithBaseURL加载html。这样就可以在html中使用 file:///android_asset/xxx.png 的链接来引用包里面assets下的资源了。示例如下:
private void loadWithAccessLocal(final String htmlUrl) {
new Thread(new Runnable() {
public void run() {
try {
final String htmlStr = NetService.fetchHtml(htmlUrl);
if (htmlStr != null) {
TaskExecutor.runTaskOnUiThread(new Runnable() {
@Override
public void run() {
loadDataWithBaseURL(htmlUrl, htmlStr, “text/html”, “UTF-8”, “”);
}
});
return;
}
} catch (Exception e) {
Log.e(“Exception:” + e.getMessage());
}
TaskExecutor.runTaskOnUiThread(new Runnable() {
@Override
public void run() {
onPageLoadedError(-1, “fetch html failed”);
}
});
}
}).start();
}
上面几点需要注意:
从网络上下载html的过程应放在工作线程中
html下载成功后渲染出html的步骤应放在UI主线程,不然WebView会报错
html下载失败则可以使用我们前面讲述的方法来显示自定义错误界面
ViewPager里非首屏WebView点击事件不响应
如果你的多个WebView是放在ViewPager里一个个加载出来的,那么就会遇到这样的问题。ViewPager首屏WebView的创建是在前台,点击时没有问题;而其他非首屏的WebView是在后台创建,滑动到它后点击页面会出现如下错误日志:
20955-20968/xx.xxx.xxx E/webcoreglue﹕ Should not happen: no rect-based-test nodes found
解决这个问题的办法是继承WebView类,在子类覆盖onTouchEvent方法,填入如下代码:
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY());
}
return super.onTouchEvent(ev);
}
该方法的最先提出在WebView in ViewPager not receive user inputs。
WebView硬件加速导致页面渲染闪烁
4.0以上的系统我们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是,当WebView视图被整体遮住一块,然后突然恢复时(比如使用SlideMenu将WebView从侧边滑出来时),这个过渡期会出现白块同时界面闪烁。解决这个问题的方法是在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启,代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
避免addJavaScriptInterface带来的安全问题
使用开源项目Safe Java-JS WebView Bridge可以很好替代addJavaScriptInterface方法,同时增加了异步回调等支持,并且不存在了安全风险。
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean ret = super.onTouchEvent(ev);
if (mPreventParentTouch) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
requestDisallowInterceptTouchEvent(true);
ret = true;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
requestDisallowInterceptTouchEvent(false);
mPreventParentTouch = false;
break;
}
}
return ret;
}
public void preventParentTouchEvent () {
mPreventParentTouch = true;
}
代码控制的关键在于mPreventParentTouch这个变量,mPreventParentTouch默认为false,当用户touchdown页面元素时通知该WebView将mPreventParentTouch设置为true。示意代码如下:
关于web页面如何通知WebView(即调用Java方法)请参看第8条。
刚提到了上面是一种简单的做法,并不能很好的解决手指滑动过快带来的误操作问题,即当用户快速地滑动时,还是有一定机率会出现ViewPager拦截TouchMove事件而发生了Tab切换而非页面元素做出了响应。要完美解决此问题,就要用到稍微复杂一点的方法(仅是整体消息传递流程复杂一点)。
首先假设在ViewPager之上还有一个父元素叫做ParentViewOnViewPager,当我们接收到页面preventParentTouchEvent通知时就先于ViewPager而进行拦截。如下:
ParentViewOnViewPager.java
public class ParentViewOnViewPager extends FrameLayout {
private MineWebView mDispatchWebView;
public void preventParentTouchEvent (WebView view) {
mDispatchWebView = (MineWebView)view;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_MOVE && mDispatchWebView != null) {
mDispatchWebView.ignoreTouchCancel(true);
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mDispatchWebView != null){
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
mDispatchWebView.onTouchEvent(ev);
break;
default:
mDispatchWebView.ignoreTouchCancel(false);
mDispatchWebView.onTouchEvent(ev);
mDispatchWebView = null;
break;
}
return true;
}
return super.onTouchEvent(ev);
}
}
即当ParentViewOnViewPager接收到通知时,发起TouchEvent拦截,将拦截到的Touch事件转嫁到装载页面的mDispatchWebView进行事件派发。这样就直接跳过了ViewPager这一层。这里需要注意的是当ParentViewOnViewPager发起拦截时,WebView会接收到一个TouchCancel事件,WebView应该忽略这个事件,以避免页面接收到这个事件而打断整个处理流程。如下代码所示:
MineWebView.java
public class MineWebView extends WebView {
boolean mIgnoreTouchCancel;
public void ignoreTouchCancel (boolean val) {
mIgnoreTouchCancel = val;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return ev.getAction() == MotionEvent.ACTION_CANCEL && mIgnoreTouchCancel || super.onTouchEvent(ev);
}
}
另外针对这种解决方案,页面端的JS脚本不用做任何变动。
42.如何优化布局?
1、场景:些布局会隐藏显布局会展示
把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。
2、替换方式:
推荐的做法是使用android.view.ViewStub,ViewStub是一个轻量级的View,使用非常简单:
mViewStub = (ViewStub) this.findViewById(R.id.viewstub);
mViewStub.inflate();
它是一个占用资源非常小的控件,相当于一个“占位控件”。使用时可以为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时或调用了ViewStub.inflate()的时候,ViewStub所指向的布局就会被inflate实例化,此布局文件直接将当前ViewStub替换掉,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub在运行时动态显示布局,节约内存资源。
目的: 正确把握住ViewStub的应用场景非常重要,因为使用ViewStub可以优化布局,一般应用在当前布局或控件在用户使用较少情况下,这样可以提高性能,节约内存,加快界面渲染
3、布局重用可以通过这个标签直接加载外部的xml到当前结构中,是复用UI资源的常用标签
4、减少视图层级
标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。多用于替换FrameLayout(因为所有的Activity视图的根结点都是FrameLayout,如果当前的布局根结点是Framelayout,那么可以用merge替代,减少多余的层级)或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,又include引入了一个垂直布局,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI渲染。这时可以使用标签进行优化。
43.强引用,软引用,弱引用,虚引用的区别?
1、强引用
如果一个对象具有强引用,GC绝不会回收它;当内存空间不足,JVM宁愿抛出OutOfMemoryError错误。一般new出来的对象都是强引用
2、软引用
如果一个对象具有软引用,当内存空间不足,GC会回收这些对象的内存,使用软引用构建敏感数据的缓存。
3、弱引用
如果一个对象具有弱引用,在GC线程扫描内存区域的过程中,不管当前内存空间足够与否,都会回收内存,使用弱引用 构建非敏感数据的缓存。
4、虚引用
虚引用主要用来跟踪对象被垃圾回收的活动。
虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解
被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
44.二维码的原理?二维码可以加前景色吗?
暂没整理
45.Apk怎么打包签名的? 根据自己的理解描述下Android数字签名?
数字签名的两种模式
我们都知道Android系统不会安装运行任何一款未经数字签名的apk程序,无论是在模拟器上还是在实际的物理设备上。所以我们会一个疑问,为何在日 常开发过程中我没有进行任何签名的操作,程序都会在模拟器和真机上运行?下面我们来讲讲APK程序的两种模式: 调试模式(debug mode)和发布模式(release mode)
1、调试模式(debug mode) : 在调试模式下,ADT会自动的使用debug密钥为应用程序签名,因此我们可以直接运行程序。
debug密钥:一个名为debug.keystore的文件。
存放位置:C:\Users\Xiaopeng.android\debug.keystore Xiaopeng对应替换为自己操作系统的用户名
两个风险:
debug签名的应用程序这样两个风险:
1debug签名的应用程序不能在Android Market上架销售,它会强制你使用自己的签名;
2debug.keystore在不同的机器上所生成的可能都不一样,就意味着如果你换了机器进行apk版本升级,那么将会出现上面那种程序不能覆盖安装的问题。
2、发布模式(release mode) : 当要发布程序时,开发者就需要使用自己的数字证书给apk包签名。
Android程序编译、打包、签名、发布的种方式
方式一:使用eclipse+ADT编译打包
方式二:命令行手动编译打包
方式:使用ant自动编译打包
1.利用Eclipse工具打包签名AndroidApk文件:http://jingyan.baidu.com/article/15622f247bdd1bfdfcbea5fd.html
1.择你要打包成Apk文件的项目点击右键,你会看到Export这一个选项。
2.点击择导出,你会看到一个对话框选择导出Android应用。
3.双击导出Android Application 会让你择项目,直接点击下一步。
4.这个时候对话框中会叫你择你的Keystore。两个择一个用已经存在的Keystore,一个创建新的Keystore。
5.我们择创建新的Keystore。择生成的目录名字。输入密码。点击下一步。
6.这个时候需要你输入详细的Keystore信息,包括密码,使用年限,城市等等输入就是。点击下一步。直到完成。
7.这个时候你的Keystore生成完成了,重复4的步骤择导出Android工程,择使用已经存在的Keystore,输入刚开始输入的密码下一步,直到完成。输入APK生成的目录,和名字点击Finish完成。到这里你的项目打包成APK就成功了。
45.对于Android的安全问题,你知道多少 ①错误导出组件 ② 参数校验不严③WebView引入各种安全问题,webview中的js注入 ④不混淆、不防二次打包 ⑤明文存储关键信息 ⑦ 错误使用HTTPS ⑧山寨加密方法 ⑨滥用权限、内存泄露、使用debug签名
46.谈谈你对Android中Context的理解? Context:包含上下文信息(外部值)的一个参数. Android中的 Context分三种,Application Context ,Activity Context ,ServiceContext. 它描述的是一个应用程序环境的信息,通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Intent信息等
在购物模块秒杀功能是怎么做的?
从服务器拿到到时的时间 然后拿到到达时间 用countdownTime进行倒计时
okhttp和volley的区别?并写出各自的优缺点?
资料已经给大家 看一下优缺点
Glide和Picasso的区别?并写出各自的优缺点?
资料已经给大家 看一下优缺点
ListView是如何实现局部刷新的?
http://www.cnblogs.com/liuling/p/2015-10-20-01.html
http://bbs.csdn.net/topics/391909960?page=1
内存优化都是从哪些方面做的?数据库如何优化?
1.Reckon(计算)
首先需要知道你的app所消耗内存的情况,知己知彼才能百战不殆
2.Reduce(减少)
消耗更少的资源
3.Reuse(重用)
当第一次使用完以后,尽量给其他的使用
5.Recycle(回收)
返回资源给生产流
4.Review(检查)
回顾检查你的程序,看看设计或代码什么不合理的地方。
1、SparseArray替代HashMap
更加节省内存,某些情况下更高效(查找使用的是二分查找),参考
http://liuzhichao.com/p/832.html
http://android-performance.com/android/2014/02/10/android-sparsearray-vs-hashmap.html
相关的还SparseLongArray可以代替HashMap
还LongSparseArray,注意这里和SparseLongArray不一样哦,LongSparseArray是用来代替HashMap
2、用一维数组代替多维数组
多维数组占的内存空间会多很多,效率也低
关于数组的内存空间可以参考
http://www.javamex.com/tutorials/memory/object_memory_usage.shtml 介绍JAVA对象的内存占用
http://www.javamex.com/tutorials/memory/array_memory_usage.shtml介绍JAVA数组的内存占用
3、布局方面使用merge、include、viewstub
viewstub可以延迟渲染,对于非立刻需要显示的界面可以使用viewstub,在真正需要的时候才渲染
4、Message不new,用handler.obtainMessage()
Message内部有个静态缓存池是链表结构的,obtain实际上就是把链表的头部元素摘下来
5、空闲时预读
在空闲时对获取成本较高的数据(如要读取本地或网络资源进行预读是提高性能的效手段。为了给用户带来更好的交互体验,提高响应性,很多网络应用(如新闻阅读类应用都在启动的时候进行预读,把网络数据缓存到sdcard或者内存中。
http://blog.csdn.net/mylzc/article/details/6802935
6、内存间传数据用Parcelable,需保存或网络传数据用Serializable
Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化
7、图片压缩
加载图片前,先预估图片大小,ImageView大小,进行适当压缩,通过设置BitmapFactory.Options中inSampleSize的值就可以实现
http://blog.csdn.net/guolin_blog/article/details/9316683
8 LruCache管理内存,DiskLruCache管理磁盘
9 通过广播需要获取当前的电量等级,当电池电量低于某一个级别的时候,您的应用程序应当降低后台服务的更新频率来尽量减小电量的消耗
10 使用RelativeLayout代替嵌套LinearLayouts,尽可能保持“扁平化”布局,减少创建的对象数量
11 反射效率低,所以可以在静态代码块里调用Class.forName和Class.getMethod来确认方法是否存在,如果性能要求不高那直接用Method.invoke好了。
13、使用较小的数据类型来操作一般情况下会提高效率,但是也不是完全这样,如果小于寄存器的位数,反而会引入额外指令(比如类型转化)
14、short排序的速度比远远快于int和long,因为他使用的不是快排而是计数排序,复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法,short范围是-32768~32767
http://www.cnblogs.com/kaituorensheng/archive/2013/02/23/2923877.html
15、JNI访问java对象或类的成员和方法需要获取jfieldID,在类加载的时候就获取所有id会提高效率(android性能优化P51)
16 、某些时候,应用如果没有在前台可以注销广播以减少功耗,在onPause里注销,在onResume里注册
17、foreach方式最好不要再ArrayList内使用,因为他本质上使用iterator方式,不如常规for循环效率高
数据库优化
1.由于SQLiteDatabase对象较为耗费资源,所以我们在使用完SQLiteDatabase对象之后,必须立即关闭它,避免它继续占用资源,否则我们继续程序可能会导致OOM或者其他异常;
2.同理,我们在使用完cursor之后也应该立即关闭cursor,避免资源浪费;
3.我们在关闭数据库之前,必须将取得的数据保存到Map或者List中,否则关闭数据库之后,数据也会随之消失;
4.使用明确的查询语句,在数据库的查询中避免使用select * from table这样的语句,我们一般不会用到全部的数据,但这样查询不仅浪费时间,也浪费android有限的内存,所以我们必须明确查询目标,例如:select id,name from people;
5.在较为频繁的数据库操作中(例如批量插入数据),可以使用数据库事物来处理频繁操作(如果只有一个数据操作,则android默认使用事物);
6.在sqlite数据库中使用索引,给经常查询的列创建索引,但索引不适用于较大的数据库,较大的数据库创建索引会耗费太多的时间,而且每次改动一条数据,整个索引都将重新创建;
内存泄露
单例造成的:由于单例的静态特性使得其生命周期跟应用的生命周期一样长,所以如果使用不恰当的话,很容易造成内存泄漏。
Handler 造成的内存泄漏:Handler、Message 和 MessageQueue 都是相互关联在一起的,万一 Handler 发送的 Message 尚未被处理,则该 Message 及发送它的 Handler 对象将被线程 MessageQueue 一直持有。
尽量避免使用 static 成员变量:如果成员变量被声明为 static,那我们都知道其生命周期将与整个app进程生命周期一样。
资源未关闭造成的内存泄漏:ABCRO
池(PooL):
(1)对象池使用的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。 并非所有对象都适合拿来池化――因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。
(2)线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
比如:一个应用要和网络打交道,有很多步骤需要访问网络,为了不阻塞主线程,每个步骤都创建个线程,在线程中和网络交互,用线程池就变的简单,线程池是对线程的一种封装,让线程用起来更加简便,只需要创一个线程池,把这些步骤像任务一样放进线程池,在程序销毁时只要调用线程池的销毁函数即可。
java提供了ExecutorService和Executors类,我们可以应用它去建立线程池。
通常可以建立如下4种:
/** 每次只执行一个任务的线程池 */
ExecutorService singleTaskExecutor = Executors.newSingleThreadExecutor();
/** 每次执行限定个数个任务的线程池 */
ExecutorService limitedTaskExecutor = Executors.newFixedThreadPool(3);
/** 所有任务都一次性开始的线程池 */
ExecutorService allTaskExecutor = Executors.newCachedThreadPool();
/** 创建一个可在指定时间里执行任务的线程池,亦可重复执行 */
ExecutorService scheduledTaskExecutor = Executors.newScheduledThreadPool(3);
更多关于线程池的内容我推荐这篇文章:http://www.xuanyusong.com/archives/2439
布局优化:
a)ViewStub 是一个不可见的,大小为0的View,最佳用途就是实现View的延迟加载,避免资源浪费,在需要的时候才加载View
b)布局重用
可以通过这个标签直接加载外部的xml到当前结构中,是复用UI资源的常用标签
c)减少视图层级
描述一下Intent,IntentFilter和PendingIntent?
说下各自是干什么的都可以
JNI调用流程?
暂无整理
AsyncTask和Handler使用在哪些场景?AsyncTask它的缺陷是什么?如何解决?
结合实际项目中的应用就行 比如前者下载东西时加载进度 后者进程间通信
如果在工作中遇到你不会的技术时怎么解决?
什么情况下导致application多次初始化资源:一般来说application的onCreate()方法只会执行一次,如果应用中采用多进程的方式,onCreate()方法会执行多次,根据不同的进程的名称进行不同的初始化
UI设计师根据IOS像素尺寸出图,根据IOS的像素给出Android(pd)的尺寸:
Android的dp尺寸=IOS像素尺寸*75%2/3。
12.大致写一下项目框架搭建的过程:
13.A(Activity)设置为singleTask模式,跳转到B(activiity)中并返回传值给A,怎么处理:@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
当一个Activity B跳转到我们的singleTask Activity A时,我们在getIntent()前会先执行onNewIntent()方法,在这个方法里,我们将接收到的新的Intent覆盖了第一次启动Activity A用的Intent,这样我们在getIntent()的时候,拿到的Intent就是带有B传给A带有Bundle值的Intent了。
我们将onNewIntent(Intent)方法写在了我们的Activity A里面,成功的得到了B传给A的数
延生:Activity的四种启动模式
14.Activity的生命周期
15.fragment的生命周期
16.服务的神功周期:
17.OOR
18.ANR
19.oor
20.Android中,调用jni的过程
21.框架设计模式
22.Java.io包中的-----类主要对object对象的读写
23.常用算法
24.如果一张10241024大小的图片,以argb色按照原始大小加载到内存中占几兆?
25.嵌入式操作系统内存管理有几种?各有什么特性?
26.设计模式
32、请列举内存溢出和内存泄漏的例子
1)内存溢出
1、资源释放问题:
程序代码的问题,长期保持某些资源(如Context)的引用,造成内存泄露,资源得不到释放
2、对象内存过大问题:
保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制
3、static:
static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context的情况最多),这时就要谨慎对待了
附加题:请列举内存溢出和内存泄漏的例子 5 + 5
1)内存溢出
1、资源释放问题:
程序代码的问题,长期保持某些资源(如Context)的引用,造成内存泄露,资源得不到释放
2、对象内存过大问题:
保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制
3、static:
static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context的情况最多),这时就要谨慎对待了
2)内存泄漏
比如Activity中发送了延迟消息,在onDestory中没有销毁延迟消息
比如Activity中绑定了服务,在退出Activity时没有及时解绑服务
比如Activity中动态注册了广播接收器,但在退出Activity时没有及时解注册广播接收器
安卓面试备考
面试题一:AIDL的全称是什么?如何工作?
Android interface definition language (android接口定义语言) ,
用来跨进程的访问方法, 像 游戏中调用支付宝接口就是用的这个。
访问远程的服务的方法. 如何工作。
面试题二:Android程序运行时权限与文件系统权限的区别?
程序运行时权限:Android程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求,打电话,访问网络,获取坐标,写sd卡,读写联系人等..安装的时候会提示用户。
文件系统权限:其实就是Linux的文件系统权限,比如-rw------ 私权限 -rw-rw-rw- 全局可读可写,(777是可读可写可执行1+2+4)还有sharedpreference里面的Context.Mode_private
Context.Mode.world_read_able Context.Mode_world_writeable夜市文件系统的权限。
面试题:系统上安装了多种浏览器,能否指定某浏览器访问指定页面?
找到对应的浏览器的意图,传递数据URI , 激活这个意图
Intent .setAction(VIEW)
Intent intent = new Intent();
// com.android.browser/.BrowserActivity
intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");
Intent.setdata(uri);
像腾讯那个检测是否安装自己的浏览器,方法是queryintentactivity(),获取到所有Action。然后查里面有没有自己浏览器的action,没有的话就提示用户。
面试题四:对主线程的理解:
耗时的不能再主线程做,会anr异常,像安卓四大组件都是在主线程里面。
面试题五:Framework工作方式及原理,Activity是如何生成一个view的,机制是什么?
所的框架都是基于反射 和 配置文件(manifest)的。
Activity创建一个view是通过 ondraw 画出来的, 画这个view之前呢,还会调用onmeasure方法来计算显示的大小.但是Surfaceview 是直接操作硬件的,因为 或者视频播放对帧数有要求,onDraw效率太低,不够使,Surfaceview直接把数据写到显存。
面试题六:android本身的一些限制,比如apk包大小限制,读取大文件时的时间限?
如果在broadCast里面不能超过10秒,
在service里面不能超过20秒
在主线程里面不能超过5秒。
像些系统不能安装大文件,我们一般是把素材文件放到一个素材包而不是安装包,两者区分开。
面试题七:如何加载的音乐信息,如何改善其效率?
Android提供mediascanner,mediaStore等接口, 音乐文件的信息都会存放到系统的数据库表中,可以通过content provider获取,
显示出来,改善效率,是个常见问题, 可以从以下几个方面作答,
1.分批加载数据, 延时加载数据, 合理使用缓存等…
2.预先加载一些 都会的使用的大的class的字节码, 提前加载.
3.时间换时间
4.空间换时间
面试题八:ListView如何提高其效率?
1.异步加载数据, 分页加载数据,使用 onscallLinster();
2.Static class ViewHolder
使用静态的view对象 避免创建过多的view.
把下载后的数据缓存到数据库里
客户端和服务器 协同 作战,比如说客户端请求图片的时候,先把自己的图片数据和服务器比对一下,如果服务器图片未更新,就拿缓存。看客户端图片的If-modify-since :属性就只掉最后修改时间,在网易新闻客户端就用到了这个。
面试题九:启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?
如果在点击图标进入,就会开启一个新的任务栈,如果startActivity的话默认情况不会开启一个新的任务栈。只有我们在activity制定Flag-- flag_activity_new_task才会开新的。
面试题十:Android程序与Java程序的区别?
Android程序用android sdk开发,java程序用javasdk开发.
Android SDK引用了大部分的Java SDK,少数部分被Android SDK抛弃,比如说界面部分,java.awt swing package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。
android sdk 添加工具jar httpclient , pull openGL
1.6的 不支持 httpUrlconning 获取 last-modified 信息的处理
simpleDataFormat 在java中年时小写,在安卓里面是大写。
面试题十一:在Android中,怎么节省内存的使用,怎么主动回收内存?:
1. 尽量多使用内部类 提高程序效率 2. 把bean里面的字段都定义成public :Bean private public 3. 回收已经使用的资源 4. 合理的使用缓存 5. 合理设置变量的作用范围 比如不是全局使用就不要定义为application对象 6. 未来的某一段时间执行 System.gc();面试题十二:不同工程中的方法是否可以相互调用?
可以,aidl就是这样子的。支付宝服务。
面试题十:dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念?
Dvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面,
每个android程序系统都会给他分配一个单独的liunx uid(user id),
每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程.
面试题十四:如何判断是否SD卡?
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
面试题十五:嵌入式操作系统内存管理哪几种, 各有何特性。?
这是大学里面操作系统的知识,包括纯分页,纯分段和段页式存储。
面试题十六:什么是嵌入式实时操作系统, Android 操作系统属于实时操作系统吗?
实时操作系统分为两种,硬实时和 软实时,硬实时一般用在军工,比如火星探测器,航空啊等等,是一旦又中断产生就会立即响应中断,而软实时是基于一套算法,可以不立即响应中断,我们一般的操作系统都是软实时操作系统,Android也不例外。
面试题十七:Linux中跨进程通信的几种方式?
管道( pipe ),信号量( semophore ),信号 ( sinal ),共享内存( shared memory ),套接字( socket )。
面试题十八:谈谈对Android NDK的理解:
1.实时性要求高的软件。比如游戏,图形渲染, opencv (人脸识别)
2.调用C或者c+++的代码库,第一是性能好,第二是人家写好了直接能用了,而java的代码库太少了。ffmpeg , rmvb mp5 avi 高清解码. ffmpeg, opencore
3.优点:效率高,缺点:出错之后不好调试,写起来也麻烦。软件升级的时候也不方便。
面试题十九:Android UI中的View如何刷新。
分主线程和子线程中两种情况:‘
主线程用控件调用Invalide()方法。iv.invalidate();
子线程用控件调用postInvalidate();—iv.postInvalidate();
Android 面试题总结之Android 基础
2016.5.31红黑联盟
本章系Android基础将会总结了Android 布局常见面试问题。其实对于基础方面Android 开发来说,经常面试无非就是UI,网络,数据库,这三大方面,本章节总结了笔记经典的问题,希望对广大Android开发者,有所帮助。
Android 中常用的布局都哪些?
FrameLayout RelativeLayout LinearLayout AbsoluteLayout TableLayout GrideLayout(Android 4.0 推出)
谈谈 UI 中, Padding 和 Margin 有什么区别?
android:padding和android:layout_margin的区别,其实概念很简单,padding 是站在父 view 的角度描述问 题,它规定它里面的内容必须与这个父 view 边界的距离。margin 则是站在自己的角度描述问题,规定自己和其他(上下左右)的 view 之间的距离,如果同一级只有一个 view,那么它的效果基本上就和 padding 一样了。
使用权重如何让一个控件的宽度为父控件的 1/3?
可以在水平方向的 LinearLayout 中设置 weightSum 为 3,然后让其子控件的 weight 为 1,那么该子控件就是 父控件的 1/3。Android 中布局的优化措施都有哪些?
这个问题也属于Android 性能优化的一部分。
1、尽可能减少布局的嵌套层级
可以使用 sdk 提供的hierarchyviewer工具分析视图树,帮助我们发现没有用到的布局。
2、不用设置不必要的背景,避免过度绘制 比如父控件设置了背景色,子控件完全将父控件给覆盖的情况下,那么父控件就没有必要设置背景。
3、使用标签复用相同的布局代码
4、使用标签减少视图层次结构
该标签主要两种用法:
第一个是让该布局在其父控件中的布局方式,第二个是该布局布置其字对象的布局方式。
关于LinearLayout 的权重算法?
如上代码,如何计算出每一个Button的宽度?
布局大小=剩余空间大小权重所占比例+设定的宽度
图片加载失败,点击重新加载
scrollView 嵌套 listview 方式除了测量还有什么方法?
手动设置 ListView 高度
经过测试发现,在 xml 中直接指定 ListView 的高度,是可以解决这个问题的,但是 ListView 中的数据是可变的,实际高度还需要实际测量。
于是手动代码设置 ListView 高度的方法就诞生了。使用单个 ListView 取代 ScrollView 中所有内容
如果满足头布局和脚布局的 UI 设计,直接使用 listview 替代 scrollview使用 LinearLayout 取代 ListView
既然 ListView 不能适应 ScrollView,那就换一个可以适应 ScrollView 的控件,干嘛非要吊死在 ListView 这一棵树上呢?
而 LinearLayout 是最好的选择。但如果我仍想继续使用已经定义好的 Adater 呢?我们只需要自定 义一个类继承自 LinearLayout,为其加上对 BaseAdapter 的适配。自定义可适应 ScrollView 的 ListView
这个方法和上面的方法是异曲同工,方法 3 是自定义了 LinearLayout 以取代 ListView 的功能,但如果 我脾气就是倔,就是要用 ListView 怎么办?
那就只好自定义一个类继承自 ListView,通过重写其 onMeasure 方法,达到对 ScrollView 适配的效果。
dp 和 px 之间的关系?
dp:是 dip 的简写,指密度无关的像素。 指一个抽象意义上的像素,程序用它来定义界面元素。一个与密度无关的,在逻辑尺寸上,与一个位于像素密度为 160dpi 的屏幕上的像素是一致的。 要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式: pixels=dips*(density/160)。举个例子,在 DPI 为 240 的屏幕上,1 个 DIP 等 于 1.5 个物理像素。
布局时最好使用 dp 来定义我们程序的界面,因为这样可以保证我们的 UI 在各种分辨率的屏幕上都可以正常显示。
/** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp / public static int px2dip(Context context, float pxValue) { final float scale = context.getResources.getDisplayMetrics.density; return (int) (pxValue / scale + 0.5f); } /* * 根据手机的分辨率从 dip 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources.getDisplayMetrics.density; return (int) (dpValue * scale + 0.5f); }
于是乎,应该也能理解android项目中的图片资源文件,一般我们需要在以下几个文件夹中提供不同大小的图片。
xhdpi: 2.0 hdpi: 1.5 mdpi: 1.0 (baseline) ldpi: 0.75
如果一张放在mdpi 的图片加载到内存中大小是 10m ,那么遇到hdpi的设备图片加载到内存中大小是15m。
什么是屏幕尺寸、屏幕分辨率、屏幕像素密度?
屏幕尺寸是指屏幕对角线的长度。单位是英寸,1英寸=2.54厘米
屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1像素点,一般是纵向像素横向像素,如1280×720
屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写,像素密度和屏幕尺寸和屏幕分辨率关。
Android 样式和主题?
样式(Styles):
Android 允许在外部样式文件中定义 Android 应用程序的 Look 和 Feel ,你可以将定义好的样式应用在不同的视图(Views)上。你可以在 XML 文件中定义样式,并将这些样式运用到不同的组件上。使用XML这种方式定义样式,你只需要配置一些通用的属性,以后如果需要修改样式,可以集中修改。
属性(Attributes):
你也可以将单个属性应用到 Android 样式上,通常会在自定义View 的时候,自定义属性。
主题(Themes):
主题相比单个视图而言,是应用到整个 Activity 或者 application 的样式
如何将Acitivity中的Window的背景图设置为空?
getWindow.setBackgroundDrawable(null);android的默认背景是不是为空。
布局适配
在明白上面基础问题的一些基本概念后,这里总结了一些布局适配的经验。
在Android 中有4种普遍尺寸:小(small),普通(normal),大(large),超大(xlarge)
常见的普遍分辨率:低精度(ldpi), 中精度(mdpi), 高精度(hdpi), 超高精度(xhdpi) 1080P(xxhdpi)
基本设置
在中Menifest中添加子元素
android:anyDensity=”true”时,应用程序安装在不同密度的终端上时,程序会分别加载xxhdpi、xhdpi、hdpi、mdpi、ldpi文件夹中的资源。
相反,如果设为false,即使在文件夹下拥有相同资源,应用不会自动地去相应文件夹下寻找资源
适配方案:
使用wrap_content、math_parent、weight wrap_content:
根据控件的内容设置控件的尺寸 math_parent:根据父控件的尺寸大小设置控件的尺寸 weight:权重,在线性布局中可以使用weight属性设置控件所占的比例
使用相对布局,禁用绝对布局
创建不同的layout:每一种layout需要保存在相应的资源目录中,目录以-为后缀命名。例如,对大尺寸屏幕(large screens),一个唯一的layout文件应该保存在res/layout-large/中。
使用9-patch PNG图片:当我们需要使图片在拉伸后还能保持一定的显示效果,比如,不能使图片中的重要像素拉伸,不能使内容区域受到拉伸的影响,我们就可以使用.9.png图来实现Drawable属于轻量级的、使用也很简单,Android把可绘制的对象抽象为Drawable,不同的图形图像资源就代表着不同的drawable类型, 在实际的开发过程中使用@drawable来使用drawable资源。关于Drawable更多的请看下图
图片加载失败,点击重新加载
Android 5.0 新特性–使用SVG图片资源
SVG的全称是Scalable Vector Graphics,叫可缩放矢量图形。它和位图(Bitmap)相对,SVG不会像位图一样因为缩放而让图片质量下降。
优点:
简单来说,View是Android系统在屏幕上的视觉呈现,也就是说你在手机屏幕上看到的东西都是View。
View是如何绘制出来的?
View的绘制流程是从ViewRoot的performTraversals方法开始,依次经过measure,layout和draw三个过程才最终将一个View绘制出来。
后面的章节会详细讲View 绘制过程,这里只是基础略带一下。
View是怎么呈现在界面上的?
Android中的视图都是通过Window来呈现的,不管Activity、Dialog还是Toast它们都有一个Window,然后通过WindowManager来管理View。Window和顶级View——DecorView的通信是依赖ViewRoot完成的。
关于Android View控件的理解
Android中控件大致被分为两类ViewGroup,View。ViewGroup作为容器管理View。Android视图,是类似于Dom树的架构。父视图负责测量定位绘制等操作。我们经常在用的findViewById 方法代价昂贵的原因,就是因为他负责至上而下遍历整棵控件树,来寻找View实例,在重复操作中尽量少用。现在在用的很多控件都是直接或者间接继承自View的,为了方便理解可看下图
图片加载失败,点击重新加载
View和ViewGroup什么区别?
Android的UI界面都是由View和ViewGroup及其派生类组合而成的。其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的。AndroidUI界面的一般结构可参见
图片加载失败,点击重新加载
需要注意的是嵌套次数最好不要超过10层,否则会降低效率,上图是3层
Android View刷新机制?
在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成
RelativeLayout和LinearLayout性能比较?
1.RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
2.RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
3.在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
Android UI界面架构理解
每个Activity,Dialog,Toast都包含一个PhoneWindow对象,PhoneWindow设置DecorView为应用窗口的根视图。在里面就是熟悉的TitleView和ContentView,没错,平时使用的setContentView就是设置的ContentView。
图片加载失败,点击重新加载
关于View的内容还是比较多的,而本文只是作为Android基础的知识点作为初步了解,后面会有专门的章节来讲解关于View的更多知识点。