- 1.List<T>和List<?>的区别?
List<T>是泛型,List<?>是泛型类型通配符,相当于List<? Extends Object>,他只能取元素不可以放元素。
List< ? super Long> 他可以放元素但是不支持取元素。
<? Extends superclass> 上边界限定通配符 "读"操作使用
<? Super SubClass> 下边界限定通配符 "写"操作使用
<?> 无限定通配符 只读,不能进行增加修改
- 2.泛型的种类?
泛型类,泛型接口,泛型方法
- 3.使用泛型的原因?
使用泛型和通配符提高了代码的复用性。
- 4.app启动慢,使用卡顿的原因?
1)界面绘制问题:层级太深,页面复杂,刷新不合理
2)数据处理:数据处理量过大,或者数据处理放在了ui线程。内存增加,gc频繁,引起卡顿。
- 5.Throwable、Exception� 区别?
Throwable是所有异常的基类,它包括Error错误和Exception异常。
- 6.异常情况下的activity生命周期?
点击home键后:onPause - onSaveInstanceState - onStop
重新打开手机:onStart - onRestoreInstanceState(actiivy已经被销毁) - onResume
整个异常生命周期流程:
onCreate() -onStart() - onRestoreInstanceState() - onResume() - onPause()-onSaveInstanceState()-onStop()-onDestroy()
- 7.onSaveInstanceState()和onRestoreInstanceState()在什么时候被调用?
onSaveInstanceState
1)关闭屏幕时 2)在后台内存不足时 3)按下home键
onRestoreInstanceState
1)横竖屏切换 2)当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity
- 8.怎么判断fragment是否可见?
- 9.沉浸式状态栏
颜色:
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
Window window = this.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(0xff01c7d4);
图片:
- 10.自定义组件常用的方法?
重载onMeasure(),onLayout(),onDraw()三个函数构建了自定义View的外观形象。再加上onTouchEvent()等重载视图的行为,
可以构建任何我们需要的可感知到的自定义View。
1)View本身大小多少,这由onMeasure()决定
2)View在ViewGroup中的位置如何,这由onLayout()决定
3)绘制View,onDraw()定义了如何绘制这个View。
- 11.怎么设置自定义组件的宽高?
在onMeasure()方法中使用setMeasuredDimension(100, 100)方法来设置组件的宽高。
- 12.自定义组件的方法执行流程顺序?
onMeasure()绘制大小 (他会不停的被多次调用 )
onSizeChanged()组件大小是否改变
onLayout() 自身位置
onMeasure()绘制大小(又会执行多次)
onDraw() 绘制自身 (只有当组件大小大于0的时候才走)
- 13.px和dp之间的大概关系?
dp = px/2 ;
- 14.自定义组件刷新界面的方式?
invalidate()方法,用在主线程中刷新。
postInvalidate() 方法,可直接使用在工作线程中。
- 15.onTouchEvent()方法的返回值意义?
返回false时,就是不处理该事件,传递给上层组件。
返回true时,就是该组件要消费掉该点击事件。
返回super.onTouchEvent(event)时,等于返回false。
- 16.Activity的生命周期?
onCreate() - onStart() [可见不可交互] - onRestoreInstanceState()[异常销毁时走] - onResume()[可交互] - onSaveInstanceState()[异常销毁和横竖屏切换] - onPause()[可见不可交互] - onStop()[不可见]- onDestory() [销毁]
- 17.横竖屏切换的生命周期?
1)不设置activity的configChanges时,切横屏生命周期一次,切竖屏执行两次。
2)设置configChanges = "orientation"时,横竖屏执行一次生命周期
3)设置configChanges=”orientaion|keyboardHidden”时,生命周期不执行,只会执行onConfigurationChange方法。*但是个人建议,没必要设置这些,所有的重要数据都进行在onSaveInstanceState()方法中进行保存,防止对象被回收,导致的crash问题。
- 18.activity的启动模式?和使用场景?
使用launchMode来控制启动模式和任务栈,任务栈是后进先出的结构。
1)standard:标准模式,每次都会在任务栈新建实例对象。onCreate(),onStart(),onResume()方法都会从新执行。ApplicationContext无法启动该模式的Activity。
2)singleTop:栈顶复用,实例在栈顶的话,不创建新实例。不执行onCreate()方法。但是系统会调用onNewIntent()方法。
3)singleTask:栈内复用,系统会先确认它所需的任务栈是否存在,否则先创建任务栈,然后放入实例对象。如果该栈存在,会将该实例之上的实例挤出栈,自己到栈顶。会调用onNewIntent()方法。
4)singleInstance:单实例模式,独开一个新栈,在创建一个新实例。之后不在创建新实例。在onStart()之前调用onNewIntent()方法。
使用场景:
1)singleTask:
- 19.怎么加速启动Activity?
onCreate()方法中部要进行同步耗时操作。A启动B时,不要再A中的onPause()方法中执行耗时操作,因为B的onResume()方法必须等到A的onPause()执行完才会执行。
- 20.怎么解决Activity之间切换的卡顿问题? (App卡顿问题)
首先先定位卡顿的原因,根据原因进行处理。如下:
1)使用BlockCanary开源项目处理
2)两个activity都使用了一个同步锁对象,导致卡顿。优化锁。
3)布局的层级太深,导致渲染界面慢,通过traceView工具布局分析
4)组件过多的话,可以使用html5开发
- 21.Activity的缓存方式?
可以在onSaveInstanceState中将要保存的数据保存起来,可以通过Bundle进行临时保存,然后在onCreate中的Bundle中取出来进行恢复,这样就可以避免Activity被销毁的时候数据的清空。因为onSaveInstanceState在Activity销毁之前必然会调用,所以可以在这里做缓存操作。记住,这个是系统未经你同意的时候就销毁的时候才会的。
- 22 . Service的启动方式和区别?不同启动方式的使用场景?
根据启动方式有两种,通过startService()和bindService。
根据服务类型:本地服务和远程服务
生命周期:
startService(): onCreate() - onStartCommand() - onDestroy()
bindService(): onCreate() - onBind() - onUnbind() - onDestroy()
关联:
startService():方法启动的服务,调用者与服务之间没有关联,及时调用者被销毁了,服务仍然会运行,直到使用stopService()/stopSelf()方法停止服务。
bindService(): 启动服务后,Service是一个Clicent/Server结构,调用者可以和Service进行交互。调用者和服务的生命周期绑定在一起,调用者一旦退出,服务也将终止。在onDestory()方法中使用unbindService()方法解除服务的绑定。
多次启动:
startService():多次调用只执行一次onCreate(),会多次调用onStartCommand()方法
bindService():多次调用不会多次调用onCreate()和onBind()方法
- 23.bindService的使用方法?
BindService用于绑定一个服务,这样当bindService(intent,conn,flags)后,就会绑定一个服务。这样做可以获得这个服务对象的本身,而startService(intent)只是启动服务。
第一步:继承Service,创建内部类MyBinder继承Binder。在内部类中创建一个返回该服务对象的实例方法。
第二步:重写onBind()方法,返回MyBinder实例。
第三步:调用者中实例化ServiceConnection接口的实现类。重写其中方法。
- 24.onStartCommand()方法的返回值都有哪些和区别?
1)start_no_sticky:若执行完onStartCommand方法后,系统销毁了该服务,不再重新创建服务。
2)start_sticky:若执行完onStartCommand方法后,系统销毁了该服务,那么Service会被重新创建并回掉onStartCommand()方法。(该模式适合播放音乐)
3)start_redeliver_intent:若执行完onStartCommand方法后,系统销毁了该服务,那么Service会被重新创建,回调onStartCommand方法,并将组后一个Intent回传到该方法。(该模式适合做文件下载的操作)。
- 25.怎么在android启动一个新进程?对其了解?
通过给四大组件指定androd:process属性,我们可以轻易的开启多进程模式。
android:process:”:romote”和android:”com.xx.xx”区别是,以“:”开头的为当前应用的私有进程,其他应用组件不可以进入该进程。而不以“:”开头的为全局进程,其他应用可以进入该进程。
如果没有指定process属性的话,运行在默认进程中,默认进程名为包名。
开启多进程以后会出现各种奇怪的问题。
例如:A将全局静态变量a(Manger.class文件下)从1改为2,然后开启B(单独进程),这时a变量还是1,并没有改完2。
解释:这是因为B运行在单独的进程中,android为每个应用分配了不同的虚拟机,不同的虚拟机在内存中分配不同的地址空间。这就导致在不同的虚拟机中访问同一个类的对象会产生很多副本。在进程com.wx和进程com.wx:remote中都存在着一个Manager类,并且两个类是互不干涉的,在一个进程中修改a的值,只会影响当前进程,对其他进程不会造成任何影响。
总结:所有运行在不同进程的四大组件,只要他们之间需要通过内存来共享数据的话,都是失败的。
多进程造成的问题:
1)静态成员和单例模式失效
2)线程同步机制失效
3)sp可可靠性下降
4)Application会多次创建
每次启动一个新线程,就会创建一个新的虚拟机和Application
- 26.怎么防止其他应用程序启动您的Serivce组件?
将android:exported属性设置为false。表示不允许其他应用启动本应用的组件。
- 27.Service和IntentService的区别?
Service是运行在主线程中的,如果要处理耗时操作,需要开启线程。IntentSerice是继承Service类,它为我们创建了线程,我们直接在onHandleIntent()方法中做耗时操作,执行完成后也无需手动调用stopSelf()方法,onHandleIntent()会自动调用stopSelf()。但是不可以处理多个请求。
- 28.为什么在Service中创建子线程而不是Activity中呢?
因为在Activity中创建子线程的话,线程是独立于组件而存在的,一旦Activity实例被销毁,就无法重新获取该线程的控制权。但是在Service中就不一样了,所有的Activity都可以和Serice进行关联,即使Activity被销毁,只要在从新与Service进行连接,就可继续控制该线程。
- 29.activity和service怎么进行交互?
1)Binder机制 (+接口监听)
2)AIDL
3)Broadcast
4)EventBus
- 30.Service的混合调用顺序?
1)通过startService(intent)开启服务
2)然后bindService()绑定该服务,这样可以与服务进行通信了
3)调用服务功能结束后,unbindService()解除绑定
4)最后不需要服务时,stopService()终止服务
调用unbindService将不会停止Service,而必须调用stopService 或 Service的 stopSelf来停止服务
- 31.怎么保证Service不被杀死?
1)通过priority提示服务的优先级
2)将onStartCommand()方法返回值设置成 start_sticky。
3)提升Service所在进程的优先级,使用startForeground()方法变成前台服务。
4)在Service的onDestory方法中重启Service。(发送广播,广播接收者重新启动该服务)
5)在Application加android:persisten = “true”,提高优先级,保护进程
5)监听系统广播
6)变成系统级应用
7)放一个像素在前台
- 32.android进程的优先级?
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为5个等级,它们按优先级顺序由高到低依次是:
1)前台进程
2)可视进程
3)服务进程
4)后台进程
5)空进程
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。
- 33.android提高进程优先级的方法?
1)通过startForeground()设置
2)注册文下,在application下,添加android:persistent=”true”。这样可以将该进程设置为常驻内存进程。
- 34.Binder机制的理解?
Binder是android实现进程间通信(IPC)的方式之一。Binder属于一个驱动,工作在Linux层,运行在内核空间,程序对binder的使用是通过系统的调用完成的。
binder架构是由服务器,binder驱动,app客户端三部分组成。
服务器:一个binder服务器就是一个Binder对象。当创建一个Binder对象后,内部就会开启一个线程,这个线程用于接收binder驱动发送的信息,然后执行相关服务代码。
Binder驱动:当服务器端成功创建一个Binder对象后,Binder也会创建个remote对象,该对象也是Binder类,客户端通过这个remote对象来访问远程服务。
选Binder来实现进程通信的原因是
1)可靠性(对比c/s) 2)传输性能(对比socket) 3)安全性(UID/PID)
- 35.ANR是什么?怎么造成的?
Android not responding应用程序无响应。Android执行时长为5s ,广播为 10s,服务为20s.
- 36.广播接收者的注册方式有几种,有什么区别?
静态注册和动态注册两种方式。
静态注册是在注册文件中进行注册,这种方式注册的广播是常驻型广播,及时应用程序关闭了,依然可以接受广播。使用intent-filter进行匹配广播。
动态注册是在代码中进行注册,为非常驻型广播,跟随Activity的生命周期,所以要在onDestory中对广播进行注销registerReceiver()。
- 37.广播有几种类型?
无序广播和有序广播
无序广播:通过sendBroadcast(),
有序广播:通过sendOrderedBroadcast()发送,根据广播接收者的优先级priority进行传递,中间可以对广播进行修改和中断。
- 38.Handler机制的原理?
Android提供了Handler和Looper来满足线程间的通信。
Handler:是线程间通信的桥梁,运行在主线程中。通过它进行消息的发送和接收。
MessageQueue:是消息队列,存放线程发送来的消息。
Looper:是消息队列的管理者,它会不停对进行消息队列进行轮询,然后分发消息给Handler。
工作过程:
activity在创建的时候,调用Looper.PrepareMainLooper()方法,来创建Looper对象和MessageQueue对象。当在UI线程创建Handler对象时,此时Handler与Looper,MessageQueue进行关联。当Handler对象在子线程中sendMessage时,会将消息放入消息队列中,Loopr对象通过无限循环查看的方式对消息队列进行管理,当有Message时,将Message发布给Handler对象,收到消息的Handler会调用HandlerMessage()方法进行处理。
- 39.View的绘制流程?
Measure(测量) - layout(布局) - draw(绘图) 这三大流程。分别提供了重写方法。
onMeasure :通过MeasureSpec可以获取组件的宽高模式和大小。然后通过setMeasuredDimension()方法设置实际组件的宽高。
onLayout:ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,它在onLayout中会遍历所有的子元素并调用其layout方法。
onDraw:将view绘制到屏幕上。
- 40.View的事件分发机制?
从Activity的dispatchTouchEvent()方法开始,只要没有被拦截就继续向下传递。调用ViewGroup的dispatchTouchEvent()方法中的onIterceptTouchEvent()拦截事件,如果返回ture的话,就处理该事件,调用onTouchEvent方法。如果返回false的话,就会遍历它的子View,判断是否有接收的,如果有继续向下分发。如果没有就ViewGroup自身处理。事件分发到View后,会调用dispatchTouchEvent方法,调用onTouchEvent方法判断是否拦截事件,如果拦截就消费该事件。如果不消费,就向上传递,直到Activity的OnTouchEvent方法。
- 41.invalidate和postInvalidate区别?
更新View视图的方式有两种,invalidate和postInvalidate。其中前者是在UI线程中使用。
后者可以在子线程中更新视图。
- 42.view和SurfaceView的区别?
View:必须在UI线程中更新画面,速度较慢。
SurfaceView:是View的子类。使用了双缓冲技术,在新线程中更新画面,所有刷新界面速度快。(双缓冲就是前后缓存和后台缓存,后台缓存计算场景,产生画面;前台缓存显示后台缓存已画好的画面)
- 43.android数据持久化的方式?
系统提供了三种方式用于数据持久化。1)文件存储2)sharedPreference 3 )数据库
文件存储:Context提供了openFileOutput()方法,将文件保存到/data/data/<包名>/files/目录下。openFileOutput(“filename”,Context.MODE_APPEND);
其中参数2,有两种类型:
MODE_PRIVATE——默认模式,指定文件名相同时,写入内容将覆盖原有内容
MODE_APPEND——追加模式,如果该文件已存在,则追加内容;否则创建文件
- 44.MVC和MVP的区别?
Mvc:View层可跟Model层进行交互,代码臃肿,高耦合。通信是单向
Mvp: m和v不可交互,通信是双向。
1)视图层和业务逻辑层进行分离,降低了耦合。
2)业务逻辑层可重用,一个p层可用于多个v
3)把业务逻辑放到p层,避免后台线程引用Activity导致资源无法释放,发生内存泄漏问题。
4)方便进行单元测试
5)View可进行组件化,对外只提供接口,可高度复用View。
- 45.oom是什么?
内存泄漏,对象可达但是无用,无法被释放,占用内存。
内存的分配策略:
静态存储区:常量
栈区:基本数据类型,对象引用,局部变量
堆区:对象,数组
常见的造成oom的:
1)静态集合类
2)监听器不注销
3)数据库,io,网络连接等资源未关闭
4)非静态内部类引用外部实例
5)单例模式,传人context
6)Handler+异步
7)大量使用static成员变量
- 46.android的性能优化?
通过内存管理+布局+项目结构
内存管理的优化:
1)减少对象的创建
2)使用线程池对线程进行管理
3)修改对象的引用类型
4)对图片加载的优化
5)常量使用staic final修饰符
6)合理使用容器,尽量使用优化过的数据容器,如:SparseArray
7)当界面不可见时释放内存,重写onTrimMemory()方法,来释放资源。
8)方法中如果不使用实例变量,改为静态方法。
9)减少不必要的全局变量
10)避免使用枚举
11)减少同步锁的区域范围
12)增加app的内存使用
13)谨慎使用抽象编程,会增加app的内存占用
14)在注册文件中添加android:largeHeap="true",app内存从16M增加到96M
15)使用AndResGuard对代码进行压缩和混淆
16)使用LeakCanary进行分析
布局优化:
1)使用include,viewStub,merge 减少布局层级
2)使用TraceView对布局进行分析
3)复杂的界面可以使用h5
项目结构:
1)将公用代码放入androidLib包中
其他:
静态检查+单元测试
- 47.描述一下android的系统架构?
从下往上分5层:Linux内核层(硬件驱动),系统运行层(C/C++),应用程序框架层(api),应用程序层(app)。
- 48.文件存储和数据库存储哪个效率高?
文件高。
- 49.Intent可以传递哪些数据类型?
基本数据类型,数组,序列化后的对象。
- 50.怎么将数据库(xx.db)和app一起打包发布?
将数据库(xx.db)放在res/raw/文件下,raw下的文件不会打包成二进制
- 51.res/raw 和assets的相同点和区别?
相同点:两个目录下的文件在打包后保持原样在apk包中,不会被编译成二进制。
不同点:
raw中的文件会被映射到R.java文件中,访问的时候直接使用id。不可以再有目录结构。
assets中的文件不会映射,通过AssetManager类。可再建立目录结构。
- 52.Service中可以使用Toast吗?
可以的,Toast是运行在UI线程中的。Service也是运行在Ui线程。
如果子线程使用Toast,要首先创建Looper。
- 53.ListView的优化?
1)复用convertView,减少View对象的创建
2)自定义静态ViewHolder,减少findViewById的次数
3)异步加载数据
4)分页加载
- 54.PostDelayed(run,2000)会造成线程阻塞吗?对内存有什么影响?
不会阻塞主线程
- 55.异步更新UI的方式?
1)handler.sendMessage()
2)handler.post(Runnable r)
3)使用Activity对象的runOnUiThread方法
4)使用View.post(Runnable r);
5)AsyncTask异步任务
- 56.android5.0的新特性?
1)全新的Material Design 设计风格
2)支持多种设备
3)全新风格的通知系统
4)支持64位ART虚拟机(放弃了Dalvik虚拟机)
5)电池续航改进计划(可以清除的知道电量使用)
6)改进安全性
7)蓝牙4.1
8)控件方面:
*动态切换主题
*设置View的高度和阴影
*Palette的使用
*水波纹动画
*CardView 卡片
*RecyclerView的使用
*ToolBar :代替了ActionBar
- 57.android6.0的新特性?
1)权限方面:增加运行时permissions(权限),之前是安装时会让用户同意各种权限。现在是在用的时候,在去询问。
2)电源管理:增加三种省电模式(Doze和App standby,Exemptions)
3)存储方面:可将sd卡进行加密作为内置存储。
4)主题方面:系统主题 亮/暗色切换
3)控件方面:
*TextInputLayout :炫酷的输入框
*FloatingActionButton:悬浮按钮
*SnackBar:类似Toast的提示控件
*TabLayout:跟ViewPager结合使用
*CoordinatorLayout:协调布局
- 58.android7.0的新特性?
1)多窗口的支持
2)通知增强功能
3)快速安装应用
4)随时随地低电耗模式
5)屏蔽来电号码
6)VR的支持
- 59.android序列化的方式?
Parcelable和Serializable。Serializable是java的,Parcelable是android的。
Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC,而相比之下Parcelable的性能更高
- 60.NDK是什么?
NDK是一系列工具集合,帮助开发者快速开发c/c++的动态库。
NDK性能高,保密安全。
- 61.Volley,Fresco,Glide和Picasso的区别和优缺点?
Volley(谷歌公司):特别适合数据量小,通信频繁的网络操作。volley 不适合请求较大的数据,比如下载文件,下载大图片等。
Fresco(faceBook公司):使用三级缓存,图片占用内存可及时释放。适合多图片。包太大
Picasso(square公司):图片质量高
Glide:和Picasso差不多,加载速度快,加载缓存效率高,但是Gif是杀手锏
- 62.常见的网络通信开源框架?
1)Volley(谷歌公司):网络请求排序,请求优先级处理,缓存,可取消请求,和Acitiyt的生命周期联动,activity结束时同时取消所有网络请求。
2)android-async-http:支持断点续传,默认gZip压缩,
3)retrofit:
4)Okttp:
- 63.多进程的理解?
在android中一个进程就是一个jvm。
使用多进程的好处:
1)分担主进程的压力,可用于做非读写数据外的其他耗时操作。比如开机启动这个进程。
2)守护进程,可以和主进程相互监视,有一方被杀死就重新启动对方。
缺点:
1)耗点,占用系统内存空间。新进程的创建会影响Application的实例,onCreate()会在执行一次。
2)不同进程之间内存不能共享,单例模式,sp等都会失效。
3)通信麻烦,使用AIDL。
- 64 . 通信加密的使用?
Base64:使用A-Z,a-z,0-9,+,/ 这64个字符,严格意义上说,base64不是加密算法,而是一种编码和解码算法。编码原理就是将3个字节转为4个字节。
MD5:用于密码的加密工作。MD5加密是不可逆向的,将字符转为大串整数。 AES(DES)是对称加密,但是DES非常古老了,已经可以被破解。AES是在DES的基础上,进行了增强。高效,但是存在密钥交换问题。
DH:为了解决对称加密的密钥交换问题,而产生。两端各有公钥和私钥,相互交换公钥后,在通过公钥和私钥生产本地私钥,进行加解密工作。高效
RSA:是非对称加密,公钥和私钥不同。通常用于数据加密和数字签名。效率低
- 65.Activity的创建过程?
1)在activityThread中创建Activity的对象,Activity是控制生命周期和处理事件,但是不控制视图。
2)调用handleResumeActivity方法将Activity的顶层视图DecorView添加到窗口视图window上。
3)创建ViewRoot对象,将顶层视图和窗口视图进行关联。
4)ViewRoot通过performMeasue开始绘制组件。
- 66.OkHttp的原理?
1)高效的使用http,使用okio库代替了java.io包,更快的处理数据。
2)支持http1.0/1.1,http2.0,SPDY协议
3)使用DiskLruCache内置缓存,默认是不使用的
4)要使用缓存返回体要包含“cahce-control”,如果没有,就要通过拦截器进行处理
5)使用门面模式进行设计
6)Oktttp内有线程池,Volley没有线程池
7)更快更省流量,SDPY和GZIP的支持。
8)Square出品
- 67.Picasso和Glide的区别?
Picasso是square公司出品。
Glide是google出品,基于picasso进行的二次开发,所以进行了优化和改进,但是比picasso大了400k,支持GIF动态图。
- 68.守护线程的理解?
守护线程,是指在程序运行期间在后台提供的一种通用服务线程,比如垃圾回收线程就是一个守护线程。通过调用Thread对象的setDaemon(true)方法来将线程转换为守护线程。
- 69.android的动画有几种?
三种,帧动画,补间动画和属性动画。
- 70.避免在类的内部进行Getters/Setters原因?
公共的类定义getters、setters会调用虚拟机。在类中最好通过局部变量的方式来访问。
如:
for (int i = 0; i < this.getCount();i++)
dumpItem(mItems[i]);
应该写为:
int mCount = this.getCount();
for (int i = 0; i < mCount; i++)
dumpItems(items[i]);
- 71 . 为什么尽量使用内部类?
如果该类仅仅在某个调用者使用,那么把它设计成调用者的内部类。具体的例子,参见:com.zte.resmaster.system.rescomp.dao.RescompDAOOracle。不会暴露该内部类,避免滥用而导致的维护问题。
- 72.使用弱引用WeakReference代替强引用的场景?
使用弱引用代替强引用,弱引用可以让你保持对对象的引用,同时允许gc在必要时释放该对象。
- 73 . launchMode启动模式的设置规则?
主页面设置为singleTask,一般界面设置为singleTop。
- 74 . 怎么保证应用在后台不被杀死?
早起使用Service处理,但是会有中断和被杀死情况。
使用WakeLock保持app在后台不被杀死。PowerManager负责对Android设备电源相关进行管理,而系统通过各种锁对电源进行控制,WakeLock是一种锁机制,只要有人拿着这把锁,系统就无法进入休眠阶段。
WakeLock wakeLock = null;
//获取电源锁,保持该服务在屏幕熄灭时仍然获取CPU时,保持运行
private void acquireWakeLock(){
if (null == wakeLock) {
PowerManager pm = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "PostLocationService");
if (null != wakeLock) {
wakeLock.acquire();
}
}
}
//释放设备电源锁
private void releaseWakeLock() {
if (null != wakeLock){
wakeLock.release();
wakeLock = null;
}
}
- 75 . 6.0以后sd卡文件的读写权限处理?
不仅要在注册文件下进行权限注册,同时还要在代码中进行请求权限的处理。否则会报 ErrnoException: open failed: EACCES (Permission denied) 异常。
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE);
}
}
- 76 . 使用tv.getLayoutParams()方法的小技巧?
ViewGroup.LayoutParams params = imageview.getLayoutParams();
if(params != null){ //此处一定要判空,如果组件没有父控件,返回为null
params.height = 100;
params.width = 100;
imageview.setLayoutParams(params);
}
- 77 . 怎么获取一张图片的保存时间?
一张图片是一张路径,将路径转换为File对象,然后调用File对象的lastModified()方法。就可以获取一个long类型的返回值。
- 78 .map的使用总结?
之前map的使用,一直都是用来背的。从没有真正的去理解。死记硬背又很快的忘记。正好今天做了一个微信图片展示的功能,里面涉及到了map的使用。现在进行总结下:
map是键值对集合接口。实现类 包括:HashMap,TreeMap,Hashtable,LinkedHashMap。
平时的开发中,我都是一直使用的HashMap,可能是因为好拼写吧。但是HashMap的使用场景是无序的情况下。所以想要对map中数据进行排序的话可以使用TreeMap,它是基于红黑树实现,映射是根据键的自然顺序进行排序的。
Map<String, String> map = new TreeMap<String, String>(
new Comparator<String>() {
public int compare(String obj1, String obj2) {
// 降序排序
return obj2.compareTo(obj1);
}
});
map.put("b", "ccccc");
map.put("d", "aaaaa");
map.put("c", "bbbbb");
map.put("a", "ddddd");
Set<String> keySet = map.keySet();
Iterator<String> iter = keySet.iterator();
while (iter.hasNext()) {
String key = iter.next();
System.out.println(key + ":" + map.get(key));
}
}
- 79 .加大app缓存空间的方法?
在Manifest文件Application加android:largeHeap="true"属性
- 80 .软引用和弱引用的区别?
软引用用于高速缓存。每一个对象通过软引用进行实例化,那么这个对象的数据也就会被保存起来,当需要再次调用这个对象中的数据的时候,只需要通过对象的get()方法就可以获取到该对象所保存的数据信息
//创建对象
Object obj = new Object();
//将对象放入缓存中
SoftReference sc = new SoftReference(obj);
if(sc != null){
obj = sc.get();
}
项目使用场景:Bitmap图片处理
在读取图片时,对于像素很高的图片
非常的消耗内存,andoid堆大小是16M。如果读取的图片太多,导致omm。因此使用软引用来保存Bitmap对象。流程如下:读取一张图片,这张图片被读取后就以cache的形式保存起来,当使用时,直接通过软引用的get()方法获取。这样就避免多次读取,直接从cahce中获取就可以了。当内存将要发生oom时,GC会将软引用对象释放。
public class TestActivity {
private Map<String,SoftReference<Bitmap>> cache = new HashMap<>();
public Bitmap get(String url){
if(cache.containsKey(url)){
return null;
}
return cache.get(url).get();
}
public void put(String url,Bitmap bitmap){
cache.put(url,new SoftReference<Bitmap>(bitmap));
}
}
弱引用的话,在android的部分,一般是结合handler一起使用,来避免handler导致的内存泄漏。
- 81 . 常见的oom?
对象不及时释放,static使用,线程不可控,读取Bitmap。
- 82 . ReferenceQueue引用队列是什么?
- 83 . Handler 造成内存泄漏的原因和解决办法?
只要是handler声明成static就不会造成内存泄漏,声明成弱引用activity的话,虽然也不会造成内存泄漏,但是需要等到handler中没有执行的任务后才会回收,因此性能不高。
handler之所以造成内存泄漏是因为在activity销毁的时候,handler中有未执行完的任务。那么接下来我们在Activity销毁的时候清空handelr没有执行的任务会是什么效果?(现也没有内存泄漏)
protected void onDestroy() {
super.onDestroy();
//清空所有handler中没有执行完的任务
handler.removeCallbacksAndMessages(null);
}
总结:
- handler 造成内存泄漏的原因在Activity销毁时还有未完成的任务
- 静态static Handler 可以解决内存泄漏问题
- 只使用弱引用,不使用静态也可以解决内存泄漏问题,但是要等handler中的任务全部执行完,才会释放activity
- 两种方案:1)activity销毁时,移除handler中所有任务。2)静态Handler + 弱引用(不要单独使用弱引用性能不高)
- 84 . LRU算法是什么?
最近最少使用算法,根据数据的历史访问记录来进行淘汰数据。
新数据放入表头,表满时,将表尾数据丢弃。
- 85 . LruCache类的介绍?
LruCache是android提供的一个缓存工具类,其算法是最近最少使用算法。它把最近使用的对象用“强引用”存储在LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前就从内存中移除。
- 86 . 写一个方法最重要的注意事项?(编码能力)
1.传入参数是否进行判断在使用
2.try catch 进行处理
3.对其他方法返回的参数,进行判空处理后再使用
4.复杂的工作要开线程处理
- 87 . 编写将d盘下所有mp3格式的文件地址输出?
public class Demo {
//获取D盘里所有后缀为.krc文件
private List<String> list = new ArrayList<>();
public static void main(String[] str){
/**
* 1.传入参数是否进行判断在使用
* 2.try catch 进行处理
* 3.对其他方法返回的参数,进行判空处理后再使用
*/
new Thread(new Runnable() {
@Override
public void run() {
Demo de = new Demo();
List<String> list = de.scanDFile(new File("d:\\\\"));
System.out.print(list.toString());
}
}).start();
}
private List<String> scanDFile(File file){
if(file == null ||!file.exists()) return null;
try {
File[] files = file.listFiles(); //获取该文件下所有文件
if(files == null) return null;
for (File item:files) {
if(item.isDirectory()){
scanDFile(item);
}else {
if(item.getName().endsWith(".krc")){
list.add(item.getAbsolutePath());
}
}
}
return list;
}catch (Exception ex){
System.out.print("错误");
ex.printStackTrace();
}
return null;
}
}
- 88 . 单例模式编写?
public class Demo {
private static Demo demo = null;
private Demo(){}
//双重锁 解决两个线程同时到达,同时调用 getInstance()
public static Demo getInstance(){
if(demo ==null){
synchronized (Demo.class){
if(demo == null){
demo = new Demo();
}
}
}
return demo;
}
}
- 89 . Rxandroid的使用原理?
设计模式使用到了:观察者模式和建造者模式。是一种响应式开发模式。
public void rxandroid(){
//被观察者Observable
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
if(!subscriber.isUnsubscribed()){ //是否订阅
subscriber.onNext("XXXXXXXXXXXX");
subscriber.onCompleted();
}
}
}).subscribeOn(Schedulers.io()) //被观察者在工作线程
//观察者observe
.observeOn(AndroidSchedulers.mainThread()) //观察者在主线程
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Toast.makeText(MainActivity.this,s,Toast.LENGTH_LONG).show();
}
});
}
//Rxandroid+okHttp的结合
public void rxandroid2Http() {
Observable.create(new Observable.OnSubscribe<Bitmap>() {
@Override
public void call(final Subscriber<? super Bitmap> subscriber) {
if (!subscriber.isUnsubscribed()) { //是否订阅
Request request = new Request.Builder().url(PATH).build();
new OkHttpClient().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
subscriber.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
byte[] data = response.body().bytes();
if (data != null) {
subscriber.onNext(BitmapFactory.decodeByteArray(data, 0, data.length));
}
subscriber.onCompleted();
}
}
});
}
}
}).subscribeOn(Schedulers.io()) //被观察者在工作线程
//观察者observe
.observeOn(AndroidSchedulers.mainThread()) //观察者在主线程
.subscribe(new Subscriber<Bitmap>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Bitmap s) {
}
});
}
- 90 . 数组初始化方式有几种?
静态初始化和动态初始化。
- 91 . 当一个View的大小或者位置发生改变时,绘制的流程?
任何时候View中的绘制内容发生变化时,都需要重新创建DisplayList,渲染DisplayList,更新到屏幕等操作。当一个Button的大小变为原来的两倍时,在增大Button之前,需通过父View重新计算并摆放其子View的位置。修改View的大小或者位置会触发整个HierarcyView的重新计算大小操作。
- 92 . 优化布局的方式?
使用include来复用布局,使用merge来减少层级,使用viewStub来进行延迟加载组件。
merge一般是结合include来使用的,他会直接使用父组件的属性,如果父组件是LinearLayout那么使用merge时,他就是LinearLayout了。
- 93 . 如何避免过度绘制?
1)通过Hierarchy view来查看层级情况,减少层级。去掉非必须背景,去掉非必需组件属性。activity会设置一个默认背景,这个背景DecorView背景对我们来说是无用的,但是它会被渲染一次,可以通过this.getwindow().setBackgroundDrawable(null)进行移除
2)复杂的界面使用自定义View。使用canvas.clipRect()只在可见区域进行绘制,节约cpu资源。
- 94 . cpu和gpu的区别?
cpu是中央处理器,gpu是显卡。
- 95 . 应用启动的流程?
启动分为热启动和冷启动。热启动不会创建Application对象,直接创建Activity
1)启动
2)创建Application对象 ,同时启动一个新进程
3)Application的attachBaseContext ():获取上下文
4)Application的onCreate()
5)Activity的生命周期(测量,布局,绘制)
- 96 . Application的生命周期?
1)attachBaseContext ():可获取上下文
2)onCreate()
3)onLowMemory (): 低内存时调用
4)onTrimMemory() : 系统要求应用释放内存时调用
5)onTerminate (): 应用结束时调用
- 97 . 应用启动耗时检测?
通过代码打点的方式来准确的记录每个方法的执行时间,从而知道哪些地方耗时,然后针对性的优化。
- 98 . 启动优化方案?
1)在SplashActivity启动页,进行底层初始化工作,模块初始化工作等。
2)给启动页增加个主题背景,解决启动白屏问题
3)根据任务必要性,分地方初始化不同初始工作。
- 99 .提高ListView的滑动平滑度?
在滑动时,停止Item上的线程工作,结束后,在继续进行线程工作。
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING){
workThread(false);
}else {
workThread(true);
}
}
- 100 .android 动画分几种?
帧动画,补间动画,属性动画。