Android面试题
二、Android面试题
Android面试题包括Android基础,还有一些源码级别的、原理这些等。所以想去大公司面试,一定要多看看源码和实现方式,常用框架可以试试自己能不能手写实现一下,锻炼一下自己。
(一)Android基础知识点
1、四大组件是什么
Activity、Service、Content Provider、BroadCast Receiver
2、四大组件的生命周期和简单用法
Activity:
文章图片
Service:
文章图片
用法:
步骤1:创建子类继承Service类。
需要重写父类的onCreate()、onStartCommond()、onDestroy()和onBind()方法。
步骤2:构建用于启动Service的Intent对象。
步骤3:调用startService()启动Service,调用stopService()停止服务。
步骤4:在AndroidManifest.xml里边注册Service。
Content Provider:
ContentProvider并没有Activity那样复杂的生命周期,只有简单的onCreate过程。ContentProvider是一个抽象类,当实现自己的ContentProvider类,只需要继承ContentProvider,并实现以下六个抽象方法。
onCreate():执行初始化工作。
insert(Uri,ContentValues):插入新数据。
delete(Uri,String,String[]):删除已有数据。
update(Uri,ContentValues,String,String[]):更新数据。
query(Uri,String[],String,String[],String):查询数据。
getType(Uri):获取数据的MIME类型。
BroadCast Receiver:
动态注册的广播,生命周期仅限于当前注册的Activity,离开Activity时,一定要取消注册,否则会抛出异常,但是该异常不会造成APP崩溃,但会造成内存泄漏。离开Activity后,即使没有取消注册,该广播也不会再接收消息。
静态注册广播,相比较动态注册,即使退出app,广播依然可用,通过
3、Activity之间的通信方式
Intent传值。
借助类的静态变量。
借助全局变量/Application。
借助外部工具(SharePreference,SQLLite,File,Android剪切板)。
借助Service。
4、Activity各种情况下的生命周期
(1)、Activity第一次启动生命周期:onCreate-->onStart-->onResume
(2)、当用户打开新的Activity或切换到桌面时:回调onPause-->onStop。这里有一个特殊情况,就是当打开的Activity是一个透明的Activity时,当前Activity只会执行onPause,不会执行onStop。
(3)、当用户再次回到原Activity时,回调:onRestart-->onStart-->onResume。
(4)、当用户按下Back键时,回调:onPause-->onStop-->onDestroy。
(5)、当Activity被系统回收,再次打开声明周期与(1)相同,只是生命周期相同,并不是代表所有过程都一样。
(6)、从这个生命周期来说,onCreate与onDestroy是配对的,分别标识着Activity的创建和销毁,并且只可能调用一次。
5、横竖屏切换的时候,Activity 各种情况下的生命周期
(1)、不设置Activity的Android:configChanges时,切屏会重新调用生命周期,切横屏会调用一次,切竖屏会调用两次。
(2)、设置Activity的Android:configChanges="orientation"时,切屏还是会重新调用生命周期,切横竖屏都只调用一次生命周期。
(3)、设置Activity的Android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会调用onConfigurationChanged方法。
6、Activity与Fragment之间生命周期比较
Fragment生命周期:
onAttach()
onCreate()
onCreateView()
onActivityCreate()---以上相当于Activity的onCreate方法。
onStart()---相当于Activity的onStart方法
onResume() ---相当于Activity的onResume方法
【Android面试题】onPause() ---相当于Activity的onPause方法
onStop() ---相当于Activity的onStop方法
onDestroyView()
onDestroy()
onDetach() ---相当于Activity的onDestroy方法。
7、Activity上有Dialog的时候按Home键时的生命周期
无论页面上是否有Dialog,按下Home键时都会回调:onPause-->onStop
8、两个Activity 之间跳转时必然会执行的是哪几个方法?
当从ActivityA跳转到ActivityB时,A会调用onPause(),然后B调用onCreate(),onStart(),onResume(),然后B此时覆盖在A只是,A调用onStop()方法。
如果B是透明窗口,或对话框样式,就不会调用A的onStop()方法。
如果B已经存在在Activity栈中,B就不会调用onCreate()方法。
9、前台切换到后台,然后再回到前台,Activity生命周期回调方法。弹出Dialog,生命值周期回调方法。
前台切换到后台,回调:onPause-->onStop
再回到前台,回调:onRestart-->onStart-->onResume
弹出Dialog,回调:onPause
10、Activity的四种启动模式对比
Activity四种启动模式:standard、singleTop、singleTask、singleInstance
standard:标准模式,这也是系统默认模式。每次启动Activity都会创建一个实例,不管这个实例是否已存在。
singleTop:栈顶复用模式。在这种模式下,如果新的Activity已经存在于任务栈的栈顶,那么此Activity的实例不会被重新创建,同时它的onNewIntent方法会被回调。注意:这个Activity的onCreate、onStart方法并不会被系统调用,因为它没有发生改变;如果新的Activity的实例已存在,但并不在栈顶,那么会重新创建新的Activity实例。
singleTask:栈内复用模式。这是一种单实例模式,如果任务栈内存在该Activity的实例,那么就将这个实例之上的所有Activity出栈,将这个新的Activity实例置于栈顶。
singleInstance:单实例模式。这是一种加强版的singleTask,此模式的Activity只能单独运行在一个任务栈中。
11、Activity状态保存于恢复
(1)、onSaveInstanceState()方法用来在Activity被强制销毁之前保存数据,onSaveInstanceState()方法携带一个Bundle类型的参数,Bundle提供了一系列方法用于保存数据。
(2)、onRestoreInstanceState()方法用来取的之前再onSaveInstanceState()方法中保存的值。
12、fragment各种情况下的生命周期
文章图片
(1)、Fragment在Activity中replace
新替换的Fragment:onAttach-->onCreate-->onCreateView-->onViewCreated-->onActivityCreated-->onStart-->onResume
被替换的Fragment:onPause-->onStop-->onDestroyView-->onDestroy-->onDestach
(2)、Fragment在Activity中replace并addToBackStack
新替换的Fragment(没有在BackStack中):onAttach-->onCreate-->onCreateView-->onViewCreated-->onActivityCreated-->onStart-->onResume
新替换的Fragment(在BackStack中):onCreateView-->onViewCreated-->onActivityCreated-->onStart-->onResume
被替换的Fragment:onPause-->onStop-->onDestroyView
(3)、Fragment在上述情况下进入onResume后,则进入了运行状态,以下四个生命周期将跟随所属的Activity一起调用:
onPause > onStop > onStart > onResume
13、Fragment状态保存startActivityForResult是哪个类的方法,在什么情况下使用?
Fragment调用startActivityForResult--->HostCallbacks.onStartActivityFromFragment--->Fragment.startActivityFromFragment。
14、如何实现Fragment的滑动?
ViewPager嵌套Fragment即可实现滑动。
15、fragment之间传递数据的方式?
(1)、在创建的Fragment添加tag,使用bundle传值。
(2)、使用接口回调传值。
(3)、使用开源的EventBus传值。
16、Activity 怎么和Service 绑定?
实现Service的onBind()方法以返回Service的实例给Activity。
17、怎么在Activity 中启动自己对应的Service?
Activity通过bindService()跟Service绑定。
绑定成功后,Service会将代理对象通过回调的形式传递给MyServiceConnection,这样我们就获得了Service提供的代理对象。
18、service和activity怎么进行数据交互?
(1)、binder+回调(listener)
主要思路:Activity将实例传入Service,同时利用回调更新UI。
(2)、binder+Handler
主要思路:Service持有Activity的Handler对象,Service通过往该Handler send message的方式,达到通信的目的。
(3)、广播(推荐LocalBroadCastManager)
主要思路:利用系统的LocalBroadCastManager、Service send message,Activity receive message;
(4)、开源组件(EventBus,otto)
(5)、AIDL
19、Service的开启方式
(1)、采用start启动方式
步骤:定义一个类继承Service
在Manifest.xml中配置Service
使用Context的startService(Intent)方法启动Service
不再使用时,使用stopService(Intent)方法停止Service
特点:
一旦服务开启跟调用者(开启者)就没有关系了。
开启者退出,开启者挂了,服务还在后台长期的运行。
开启者不能调用服务里的方法。
(2)、使用bind启动方式
步骤:定义一个类继承Service
在Manifest.xml中配置Service
使用Context的bindService(Intent,ServiceConnection,int)方法启动该Service
不再使用时,调用unbindService(ServiceConnection)方法停止服务。
20、请描述一下Service 的生命周期
文章图片
21、谈谈你对ContentProvider的理解
ContentProvider一般为存储和获取数据提供统一的接口,可以再不同的应用程序之间共享数据。
之所以使用ContentProvider的原因:
(1)、ContentProvider提供了对底层数据存储方式的抽象。比如下图,底层使用SQLite数据库,在用了ContentProvider封装后,即使把数据库换成MongoDB,也不会对上层数据使用层代码产生影响。
文章图片
(2)、Android框架中的一些类需要ContentProvider类型的数据。
(3)、ContentProvider为应用间提供了一个安全的环境。它准许你把自己的应用的数据根据需求开放给其他应用进行增、删、改、查,而不用担心直接开放数据库权限而带来的安全问题。
22、说说ContentProvider、ContentResolver、ContentObserver 之间的关系
ContentProvider的作用是实现各个应用程序之间的(跨应用)数据共享。
一个应用实现ContentProvider来提供内容给别的应用来操作,通过ContentResolver来操作别的应用的数据,当然在自己的应用中也是可以的。
ContentObserver-----内容观察者,目的是观察特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器,当ContentObserver所观察的Uri发生变化时,便会触发它。
23、请描述一下广播BroadcastReceiver的理解
广播即一个全局的监听器,属于Android四大组件。
Android广播分为两个角色:广播发送者,广播接收者。
应用场景:
Android不同组件间的通信(含:应用内/不同应用之间的)。
多线程通信。
与Android系统在特定情况下的通信。(如电话呼入时,网络可用时)
采用的模型:
Android中的广播采用了设计模式中的观察者模式:基于消息的发布/订阅事件模型。
模型中的角色:
消息订阅者(广播接收者)
消息发布者(广播发送者)
消息中心(AMS,即Activity Manager Service)
24、广播的分类
普通广播
系统广播
有序广播
粘性广播
App应用内广播
25、广播使用的方式和场景
(1)、静态注册
步骤:定义一个广播接收器(继承BroadcastReceiver)
在清单文件中注册该广播接收器
文章图片
在java程序中使用广播
文章图片
(2)、动态注册
步骤:定义一个广播接收器(继承BroadcastReceiver)
动态注册广播及使用
文章图片
解除广播
文章图片
在清单文件中注册该广播。
文章图片
26、在manifest 和代码中如何注册和使用BroadcastReceiver?
同上。
27、本地广播和全局广播有什么差别?
全局广播:BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通信的一种方式
本地广播:LocalBroadcaseReceiver仅在自身应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全,广播只在这个程序里,而且效率更高
28、BroadcastReceiver,LocalBroadcastReceiver 区别
同上。
29、AlertDialog,popupWindow,Activity区别
AlertDialog:用来提示用户一些信息,用起来也比较简单,设置标题内容和按钮即可。
popupWindow:就是一个悬浮在Activity上的窗口,可以用来展示任意布局。
activity:Activity是Android四大组件之一,可以用于显示View。Activity是一个与用户交互的模块。
AlertDialog是非阻塞式对话框,AlertDialog弹出时,后台还可以做事情;popupWindow是阻塞式对话框,popupWindow弹出时,程序会等待,在popupWindow退出前,程序一致处于等待,只有当我们调用了dismiss方法后,popupWindow退出,程序才会向下执行。
30、Application 和 Activity 的 Context 对象的区别
凡是跟UI相关的,都应该使用Activity作为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以。
文章图片
31、Android属性动画特性
(1)、作用对象进行了扩展:不只是View对象,甚至没有对象也可以。
(2)、动画效果:不只是4种基本变换,还有其他动画效果。
(3)、作用领域:API11之后引入的。
32、如何导入外部数据库?
(1)、将格式为.db的数据库文件放到android项目assets目录中;
(2)、在程序必要的时候,将其“拷贝”(文件读取)到Android程序的默认的数据库存储目录中,一般路径为“data/data/项目包名/databases/”;
(3)、自定义SQLiteOpenHelp类,创建一个名字和步骤(1)中一样的数据库;
(4)、按照平常的逻辑,对数据库进行增删改查。
33、LinearLayout、RelativeLayout、FrameLayout的特性及对比,并介绍使用场景。
(1)、RelativeLayout会让子View调用两次onMeasure,LinearLayout在有weight时,也会调用子View两次onMeasure。
(2)、RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂的时候,这个问题会更加严重。如果可以尽量使用padding代替margin。
(3)、在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
(4)、能用两层LinearLayout,尽量用一个RelativeLayout,在时间上此时RelativeLayout消耗更小。
34、谈谈对接口与回调的理解
接口回调:可以把使用实现了某一接口的类创建的对象的引用,赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口方法。实际上,当接口变量调用被类实现的接口方法时,就是通知响应的对象调用接口的方法,这一过程称为对象功能的接口回调。
35、回调的原理
(1)、定义回调接口,定义回调方法;
(2)、定义要设置回调机制的类,并是此类持有回调接口的指针;
(3)、在该类中初始化回调接口指针,并使用指针调用回调方法;
(4)、在该类中设置触发时机及执行的触发事件函数。
36、写一个回调demo
文章图片
文章图片
37、介绍下SurfView
SurfaceView指一个在表层的View对象。其他View是绘制在表层的上面,而SurfaceView充当表层本身。
38、RecycleView的使用
https://blog.csdn.net/weixin_42190712/article/details/80404757
39、序列化的作用,以及Android两种序列化的区别
序列化:将对象转换为字节流
(1)、在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
(2)、Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
(3)、Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性,在外界有变化的情况下。尽管Serializable效率有点低,但是还是推荐使用Serializable。
(4)、Serializable实现,只需要implements Serializable即可,这是给对象打一个标记,系统会自动将其序列化。
(5)、Parcelable实现,不仅需要implements Parcelable,还需要在类中添加一个静态成员变量CREATOR,这个变量要实现Parcelable.Ccreator接口。
(6)、Parcelable性能比Serializable好,在内存开销方面比较小,所以在内存间数据传输时,推荐使用Parcelable,如:Activity之间传值;而Serializable在数据持久化方面方便保存,在网络中传输时,使用Serializable,因为android不同版本的Parcelable可能不同,所以不推荐使用Parcelable做数据持久化。
40、差值器
Interpolator负责控制动画变化的速率,使得基本动画能够以匀速、加速、减速、抛物线速率等各种速率变化。
41、估值器
TypeEvaluator设置属性值,从初始值过度到结束值的变化具体数值。
42、Android中数据存储方式
(1)、使用SharePreference存储
(2)、使用文件存储
(3)、SQLite数据库存储
(4)、使用ContentProvider存储数据
(5)、使用网络存储。
(二)Android源码相关分析
1、Android动画框架实现原理
实现原理:每次绘制View时,ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成帧动画,如果动画没有完成,就继续调用invalidate()函数,启动下次绘制来驱动动画,从而完成整个动画的绘制。
当一个ChildView要重画时,它会调用其他成员函数invalidate()函数将通知其ParentView这个ChildView要重画。
这个过程一直遍历到ViewRoot,当ViewRoot收到这个通知后就会调用上面提到的ViewRoot中的draw函数从而完成绘制。
Android动画就是通过ParentView来不断调整ChildView的画布坐标系来实现的。
https://blog.csdn.net/qq_32816979/article/details/79746150
2、Android各个版本API的区别
https://blog.csdn.net/qq_21399461/article/details/80277472
3、Requestlayout,onlayout,onDraw,DrawChild区别与联系
requestLayout会导致调用measure()过程和layout()过程。说明:只是对View树重新布局layout过程包括measure()过程和layout()过程,不会调用draw()过程,但不会重新绘制任何视图包括该调用者本身。
onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局。)
调用onDraw()方法绘制视图本身(每个视图都需要重载该方法,ViewGroup不需要实现该方法。)
drawChild()主要是draw viewGroup中的某个View
4、invalidate和postInvalidate的区别及使用
Android中实现View的更新有两组方法,一组是invalidate,另外一组是postInvalidate,其中前者是在UI线程自身中使用,而后者是在非UI线程中使用。
invalidate是在handler中使用,postInvalidate可以直接在子线程中调用更新View。
5、Activity-Window-View三者的差别
Activity是Android四大组件之一,负责界面展示、用户交互和逻辑处理。
Window就是负责界面展示以及交互的只能部门,就相当于Activity的下属,Activity的生命周期方法负责业务的处理。
View就是放在Window容器的元素,Window是View的载体,View是Window的具体展示。
文章图片
6、谈谈对Volley的理解
Volley是Google推出的轻量级Android异步网络请求框架和图片加载框架。其适用于数据量小,通信频繁的网络操作。
主要特点:
(1)、扩展性强。Volley大多数是基于接口的设计,可配置性强。
(2)、一定程度符合Http规范,包括返回ResponseCode(2xx,3xx,4xx,5xx)的处理,请求头的处理,缓存机制的支持等。并支持重试及优先级定义。
(3)、默认Android2.3及以上基于HttpURLConnection,2.3以下基于HttpClient实现。
(4)、提供简便的图片加载工具。
7、如何优化自定义View
(1)、硬件加速就是使用GPU来代替CPU完成绘制的计算工作,它从工作分摊,和绘制机制优化来提升绘制速度。
(2)、如果我们在自定义View的时候,绘制操作不支持硬件加速,那么我们可以在自定义View中手动关闭硬件加速。
文章图片
8、低版本SDK如何实现高版本api?
Android提供了两种注解方式避免编译时报错。
@SuppressLint
@TargetApi
SuppressLint很显然的意思是忽略Lint检查,对于我们使用高版本的API来说,可以使用@SuppressLint("NewApi")的方式让Lint在编译时忽略所调用的API对版本的要求。而@TargetApi是忽略特定版本的API调用报错。
9、描述一次网络请求的流程
(1)、通过URL找到IP
(2)、对IP结果建立TCP连接
(3)、向服务器发送数据
(4)、服务器解析,并返回
(5)、浏览器解析HTML
10、HttpUrlConnection 和 okhttp关系
HttpUrlConnection是一种多用途、轻量级的HTTP客户端,使用它来进行HTTP操作可以适用于大多数应用程序。虽然HttpUrlConnection的API提供的比较简单,但是,同时使得我们可以更加容易地使用和扩展它。从Android4.4开始HttpUrlConnection的底层采用的就是okHttp。
okhttp是高性能的http库,支持同步、异步,而且实现了spdy,http2,websocket协议,api很简洁易用,和volley一样实现了http协议的缓存。picasso就是利用okhttp的缓存机制实现其文件缓存的,实现的很优雅,很正确;反例就是UIL(universal image loader),自己做的文件缓存,而且不遵守http缓存机制。
11、Bitmap对象的理解
Bitmap的构造方法不是共有的,因此外部不能通过new的方式来创建,不过可以Bitmap的createBitmap方法和BitmapFactory。
12、looper架构
有消息循环的线程一般都会有一个looper。
Looper.myLooper();获取当前的Looper。
Looper.getMainLooper();获取UI线程的Looper。
如果一个线程调用Looper.prepare(),那么系统就会自动为该线程建立一个消息队列,然后调用Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。这个如何发送消息和如何处理消息可以再其他线程中通过Handle来做。
13、ActivityThread,AMS,WMS的工作原理
AMS:统一调度所有应用程序的Activity。
WMS:控制所有的Window的显示与隐藏以及要显示的位置。
ActivityThread:Android应用主线程(UI线程)。
工作原理:
ActivityThread创建完新的进程后,main函数被加载,然后执行一个loop循环使当前线程进入消息循环,并作为主线程。接下来还会初始化很多必要的属性。
AMS:AMS从系统运行的角度来看,AMS可以分为Client端和Server端;
Client端运行在各个app进程,app进程实现了具体的Activity,Service等,告诉系统有哪些Activity、Service等,并且调用系统接口来完成显示。
Server端运行在SystemServer进程,是系统级别的ActivityManagerService的具体实现,其相应Client端的系统调用请求,并且管理Client端各个App进程的生命周期。
文章图片
WMS:为窗口分配Surface。
管理Surface的显示顺序、尺寸和位置
管理窗口动画
输入系统相关
14、自定义View如何考虑机型适配
(1)、尽量使用warp_parent、match_parent。
(2)、尽可能的使用RelativeLayout。
(3)、针对不同的机型,使用不同的布局文件放在对应的目录下,android会自动匹配。
(4)、尽量使用点9的图片。
(5)、使用与密度无关的像素单位dp、sp。
(6)、引入android的百分比布局。
(7)、切图的时候切大分辨率的图,应用到布局中,在小分辨率的手机上也会有很好的显示。
15、自定义View的事件
以点击事件为例
(1)、一个监听内部的接口,OnItemSelectListener。
(2)、接口内部有一个onItemSelect方法,Activity中使用时,通过重写该方法来实现事件的监听。
(3)、在控件中定义一个OnItemSelectListener接口的对象,并设置set方法。
16、AstncTask+HttpClient 与 AsyncHttpClient有什么区别?
AsyncHttpClient来自android-async-http库是在Apach的HttpClient库的基础上开发构建而成的,这里的异步,是指它所有的网络请求都是在app的UI线程之外的独立工作线程中执行。而开发者通过利用Android的消息处理机制,把我们所编写的回调函数放在这个回调函数的创建线程中执行(一般是UI线程),所以使用起来非常方便,除了能用在开发普通App以外,还可以用来开发Service或后台线程,android-async-http库可以自己分辨是被用在哪种应用下,不需要额外设置。
17、LaunchMode应用场景
standard模式:默认启动模式,每次启动Activity都会创建Activity的实例,并放入任务栈。
singleTop模式:栈顶模式,每次启动Activity如果Activity的实例正好处于栈顶,则重用该实例,否则,创建新的Activity实例,并放入任务栈。
singleTask模式:栈内模式,启动Activity,如果Activity的实例存在于栈内,则将该实例上部的所有Activity出栈,该实例处于栈顶,如果不存在,则创建新的实例,并放入任务栈。
singleInstance模式:栈内单例模式,每次启动Activity,都会重新创建一个新的任务栈,并创建实例放入该任务栈。
https://blog.csdn.net/android_freshman/article/details/52948124
18、AsyncTask 如何使用?
(1)、新建内部类继承AsyncTask。
(2)、定义AsyncTask的三种泛型参数。
(3)、重写doInBackground抽象方法。
(4)、重写onPreExecute抽象方法。
(5)、重写onProgressUpdate方法。
(6)、重写onPostExecute方法。
(7)、在需要启动的地方调用execute()方法。
19、SpareArray原理
SpareArray采用两个数组,用来存放key以及value值,核心思想就是通过折半查找来找到key对应的位置,然后取出值,或者插入值。
20、请介绍下ContentProvider 是如何实现数据共享的?
(1)、定义自己的ContentProvider类,该类需要继承android系统自带的ContentProvider类。
(2)、在Manifest.xml中注册ContentProvider。
(3)、其他程序使用ContentResolver来操作。
21、Android Service与Activity之间通信的几种方式
(1)、Activity调用bindService(Intent service,ServiceConnection conn,int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调的方法。
(2)、Service向Activity发送消息,可以使用广播,当然Activity要注册相应的广播接收器。比如,Service向多个Activity发送消息的时候,用这种方法更好。
22、IntentService原理及作用是什么?
IntentService是继承于Service并处理异步请求的一个类,在IntentService中有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务完成后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个,再执行第二个,以此类推。
作用:
(1)、省去了在Service中手动开启线程的麻烦;
(2)、当操作完成时,不需要手动停止Service;
(3)、方便使用。
23、说说Activity、Intent、Service 是什么关系
(1)、一个Activity通常是一个单独的屏幕,每一个Activity都被实现为一个单独的类,这些类都是从Activity基类中继承而来。Activity类会显示由视图控件组成的用户接口,并对视图控件的事件作出响应。
(2)、Intent的调用是用于屏幕间的切换。Intent描述应用想要做什么。Intent数据结构中两个最重要的部分是动作和动作对应的数据。
(3)、Service是运行在后台的组件,不于用户进行交互,可以运行在自己的进程中,也可以运行在其他程序的上下文中。需要一个Context对象调用。
(4)、Activity与Service都是四大组件之一,存在相同的基类,他们之间互相调用需要通过Intent携带信息,即Intent相当于一个消息传送者。
24、ApplicationContext和ActivityContext的区别
首先Activity.this和getApplicationContext()返回的不是同一个对象,一个是当前Activity的实例,一个是项目的Application的实例,它们各自的使用场景不同,this.getApplicationContext()取的是这个应用程序的Context,它的生命周期伴随着应用程序的存在而存在;而Activity.this取的是当前Activity的实例,它的生命周期只存活于当前Activity,这两者的生命周期是不同的。getApplicationContext()生命周期是整个应用,当应用程序销毁时,它才销毁;Activity.this的生命周期是这个Activity,当Activity销毁时,它也销毁。
25、SP是进程同步的吗?有什么方法做到同步?
一个进程时,可以用SP存储,但不支持多进程,因为它是基于单个文件的,且app对SP做了缓存,不好同步。
考虑用ContentProvider让SharePreference实现进程同步。
(1)、ContentProvider每次操作都会getSP(),保证SP的一致性。
(2)、ContentProvider基于Binder,不存在进程互斥,对同步也做了很好的封装,不需要开发者额外实现。
26、谈谈多线程在Android中的使用
在项目中比较常用的多线程操作:
(1)、Handler
(2)、AsyncTask
(3)、IntentService
27、进程和 Application 的生命周期
进程的生命周期,优先级从高到底
(1)、前台进程,比如Activity的Resume状态。
(2)、可见进程,比如主Activity上弹出一个对话框,该Activity的进程状态就为可见进程。
(3)、服务进程,比如正在运行的Service的状态。
(4)、后台进程,比如Activity,按Home键之后的状态。
(5)、空进程,该进程状态主要用来缓存进程,保存一些进程的数据,方便下次启动的时候,直接从缓存读取数据。
Application的生命周期:
(1)、onCreate在创建应用程序时调用。可以重写这个方法来实现实例化应用程序单态,以及创建和实例化任何程序状态变量和共享资源。
(2)、onLowMemory当系统处于资源匮乏的时候,具有良好行为的应用程序可以释放额外的内存。这个方法一般只会在后台进程已经终止,但是前台应用程序仍然缺少内存时调用。可以重写这个处理程序来清空缓存或释放不必要的资源。
(3)、onTrimMemory作为onLowMemory的一个特定于应用程序的替代选择,在Android4.0时引入。当运行时决定当前应用程序应该尝试减少其内存开销时调用,它包含一个level参数,用于提供请求的上下文。
(4)、onConfigurationChanged与Activity不同,在配置改变时,应用程序对象不会被终止和重启。如果应用程序使用的值依赖于特定的配置,则重写这个方法来重新加载这些值,或在应用程序级别处理配置改变。
28、封装View的时候怎么知道view的大小
getMeasuredHeight():获取控件的实际高度,包括显示的部分和超出屏幕的部分,它的值与屏幕无关。
getHeight():获取控件在屏幕中显示的高度。
getMeasuredWidth():与getMeasuredHeight()类似。
getWidth():与getHeigth()类似。
29、RecycleView原理
文章图片
RecycleView将onMeasure(),onLayout()交给了LayoutManager去处理,因此,RecyclerView设置不同的LayoutManager就可以达到不同的显示效果,因为onMeasure()和onLayout()不一样。
ItemDecoration是为了显示每个item之间分隔样式的。它本质上就是一个Drawable。当RecyclerView执行到onDraw(),这时,如果重写了该方法,就相当于在RecyclerView上画了一个Drawable表现的东西。而最后,在它的内部还有一个叫getItemOffsets()的方法,从字面来理解,它是用来偏移每个item视图的,当我们在每个item之间强行插入绘画一段Drawable,那么如果再用原来的逻辑去绘制item视图,就会覆盖掉Decoration,所以需要这个方法将每个item向后偏移,以免覆盖分隔样式。
ItemAnimation每个item在特定的情况下都会执行的动画。说是特定情况,其实就是视图在发生改变的时候,我们手动调用notifyXXX()方法的时候。通常这个时候,我们要传一个下标,那么从这个下标一直到最后,所有的item都要执行这个动画。
Adapter首先是适配器,适配器的作用都是类似的,用于提供每个item视图,并返回给RecyclerView作为其子布局添加到内部。但是,与ListView不同的是,ListView的适配器是直接返回一个View,将这个View添加到ListView的内部。而RecyclerView是返回一个ViewHolder并且不是直接将这个holder添加到视图内部,而是添加到一个缓冲区,在视图需要的时候去缓冲区找到这个holder,再间接找到holder包裹的View。
每个ViewHolder内部都包裹着一个View,并且ViewHolder必须继承自RecyclerView.ViewHolder类。这主要是因为RecyclerView内部的缓存结构并不像ListView那样缓存一个View,而是直接缓存一个ViewHolder,在ViewHolder内部又持有一个View。既然缓存的是ViewHolder,那么当然就所有的ViewHolder必须都继承同一个类。
https://www.cnblogs.com/jiangbeixiaoqiao/p/5672766.html
30、AndroidManifest的作用与理解
作用:
(1)、描述app的包名:Android设备据此区分不同的app,如果每个app是一个人的话,那么包名就是这个人的名字(为了防止恶意软件仿冒其他app,只有新的app包名和签名均与就的app相同,才能升级)。
(2)、描述app使用的Android版本信息。
(3)、描述app本身的版本信息,这样对于app两个版本,系统可以区分哪个是新版本,哪个是旧版本。
(4)、描述应用对外暴露的组件(或者叫接口)。
(5)、其他各种需要用文本直接告知系统的信息:包括权限,应用主题等。
https://blog.csdn.net/wyzzgo/article/details/73556414
(三)常见的一些原理性问题
1、Handler机制和底层实现
Handler包括四个角色:
Handler:负责发送消息处理消息。
Message:消息实体对象,handler通过sendMessage将实体放入消息队列中。
MessageQueue:存放消息的队列。
Looper:消息轮询器,不停地从消息队列中取出消息交给handler处理。
在主线程创建Handler,在需要发送消息的地方创建Message,通过handler发送。这个消息回到MessageQueue中,然后Looper将这个消息取出交给handler处理。
Handler可以有多个,但是在同一线程中Looper和MessageQueue只有一个。
2、Handler、Thread和HandlerThread的差别
Thread:普通的异步线程。
Handler:异步更新UI的,更详细的来说是用来做线程通信的,更新UI时是子线程与UI主线程之间的通信。
HandlerThread:子线程与子线程之间的通信。它内部创建一个带有Looper的线程,looper对象可以用于创建Handler类来进行调度。
3、handler发消息给子线程,looper怎么启动?
Looper.prepare()启动Looper。
Looper.loop()停止Looper循环。
4、关于Handler,在任何地方new Handler 都是什么线程下?
默认情况下,Android创建的线程没有开启消息循环Looper,主线程除外。
系统自动为主线程创建Looper对象,开启消息循环;
所以主线程中可以直接new Handler,但在子线程中不能直接new,子线程中需要:
文章图片
5、ThreadLocal原理,实现及如何保证Local属性?
当需要多线程时,有个变量恰巧不需要共享,此时就不必使用Synchronized这么麻烦的关键字来锁住,每个线程都相当于在堆内开辟一个空间,线程中带有对共享变量的缓冲区,通过缓冲区将内存中的共享变量进行读取和操作,ThreadLocal相当于线程中的内存,一个局部变量。每次可以对线程自身的数据读取和操作,并不需要通过缓冲区与主内存中的变量进行交互。并不会像synchronized那样修改主内存中的数据,再将主内存中的数据复制到线程内的工作内存。ThreadLocal可以让线程独占资源,存储于线程内部,避免线程阻塞造成CPU吞吐下降。
6、请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系
Handler获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message,再由Handler进行消息的分发和处理。
7、请描述一下View事件传递分发机制
事件分发需要View的三个重要方法共同完成:
(1)、dispatchTouchEvent(MotionEvent event)
返回值表示是否消费了当前事件。可能View本身的onTouchEvent方法消费,也可能是子View的dispatchTouchEvent方法中消费。返回true表示事件被消费,本次事件终止。返回false表示View以及子View都没有消费事件,将调用父View的onTouchEvent方法。
(2)、onInterceptTouchEvent(MotionEvent event)
事件拦截,当一个ViewGroup在接到MotionEvent事件序列的时候,首先会调用此方法判断是否需要拦截。特别注意,这是ViewGroup特有的方法,View并没有拦截方法。
返回值表示是否拦截事件传递,返回true表示拦截了事件,那么事件将不再向下分发,而是调用View本身的onTouchEvent方法。返回false表示不进行拦截,事件向下分发到子View的dispatchTouchEvent方法。
(3)、onTouchEvent(MotionEvent event)
真正对MotionEvent进行处理或消费的方法。在dispatchTouchEvent中调用。
返回值返回true表示事件被消费,本次的事件终止;返回false表示事件并没有被消费,将调用父View的onTouchEvent方法。
8、Touch事件传递流程
android的touch事件自上而下传递:经过Activity->PhoneWindow->DectorView->ContentView->ViewGroup->ChildView
文章图片
其中最主要的是Activity、ViewGroup和View的处理
文章图片
9、事件分发中的onTouch 和onTouchEvent 有什么区别,又该如何使用?
onTouch方法优先级高于onTouchEvent,会先触发。假如onTouch方法返回false,会接着触发onTouchEvent方法,反之,onTouchEvent方法并不会被调用。内置诸如click事件的实现等都基于onTouchEvent方法,假如onTouch方法返回true,这些事件将不会被触发。
https://blog.csdn.net/qq_26358311/article/details/79620964
10、View和ViewGroup分别有哪些事件分发相关的回调方法
文章图片
11、View刷新机制
View更新一共有两个方法:invalidate和postInvalidate,其中前者是在UI线程中使用,而后者是在非UI线程中使用。
12、View绘制流程
View的measure过程
文章图片
ViewGroup的measure过程
文章图片
View的layout过程
文章图片
ViewGroup的layout过程
文章图片
View的draw过程
文章图片
ViewGroup的draw过程
文章图片
13、自定义控件原理
View绘制的基本上是由measure(),layout(),draw()三个方法完成的。
https://blog.csdn.net/u012426327/article/details/77836069
14、自定义View如何提供获取View属性的接口?
(1)、在自定义View中定义一个接口。
(2)、类成员变量里声明一个这个接口的引用。
(3)、写一个方法并持有Activity实现的接口的实例。
(4)、在Activity里实现这个接口。
(5)、Activity里绑定XML中的自定义View属性,并向XML创建的自定义View对象传递Activity实现的接口对象。
https://blog.csdn.net/hystudio_lzu/article/details/79135105
15、Android代码中实现WAP方式联网
https://blog.csdn.net/asce1885/article/details/7844159
16、AsyncTask机制
AsyncTask是android提供的一种异步消息处理机制,可以直接继承AsyncTask,在类中继承抽象方法执行耗时任务,并且AsyncTask提供接口反馈当前异步操作的进度,可以通过接口实现UI更新。最终返回后台执行的结果给UI主线程,从而实现消息的异步处理。
17、AsyncTask原理及不足
AsyncTask原理:
AsyncTask内部是通过线程池+Handler实现,构造方法里边new了两个对象,在new WorkRunnable对象时通过result = doInBackground(mParams)给result赋值。然后调用postResult(result)方法,并把WorkRunnable对象当做参数传递给FutureTask。由于那是Runnable对象开启线程跑任务,跑完回调FutureTask的done()方法,这个方法又调用了postResultIfNotInvoked(get())方法。
不足:
(1)、线程池中已有128个线程,缓冲队列已满,假设此时向线程提交任务,将会抛出异常。
(2)、AsyncTask不会随着Activity的销毁而销毁,直到doInBackground()方法运行完成,假设我们的Activity销毁之前没有取消AsyncTask,这有可能造成AsyncTask崩溃,因为有可能它要处理的View已经被销毁。
(3)、假设AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。
(4)、屏幕旋转或Activity在后台被系统杀掉等情况会造成Activity再一次创建,之前运行的AsyncTask会持有销毁之前的Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
https://www.cnblogs.com/lytwajue/p/7270299.html
18、如何取消AsyncTask?
我们可以随时调用cancel(boolean)去取消这个加载任务,调这个方法会间接调用iscancelled并且返回true,调用cancel()后,在doInBackground()return后,我们将会调用onCancelled(Object)不再调用onPostExeecute(Object)方法,为了保证任务能够更快的取消掉,应该在doInBackground()方法中周期性的检查isCancelled去判断。
19、为什么不能在子线程更新UI?
Android的UI访问是没有加锁的,多线程可以同时访问更新操作同一个UI控件。也就是说访问UI的时候,android系统中的控件都不是线程安全的,这将导致在多线程模式下,当多个线程共同访问更新操作同一个控件时容易发生不可控的错误,而这是致命的。所以Android中规定只能在UI线程中更新UI,这相当于从另一个角度给Android的UI访问加了锁,伪锁。
20、ANR产生的原因是什么?
(1)、主线程执行了耗时操作,比如数据操作或网络请求。
(2)、其他进程占用CPU导致本进程得不到CPU时间片,比如其他进程的频繁读写操作可能会导致这个问题。
21、ANR定位和修正
可以查看data/anr/traces.txt查看ANR信息。
根本原因就是主线程被卡,导致应用在5秒内未响应用户的输入事件。
修正:
将耗时操作改到子线程中执行。
22、oom是什么?
oom指的是Out Of Memory,内存溢出。
23、什么情况导致oom?
OOM可能的原因:
(1)、数据库的cursor没有及时关闭
(2)、构造Adapter没有使用缓存convertView
(3)、RegisterReceiver()和unRegisterReceiver()没有成对出现
(4)、未关闭InputStream、OutputStream
(5)、Bitmap使用后未调用recycle()
(6)、static等关键字
(7)、非静态内部类持有外部类的引用,context泄漏
24、有什么解决方法可以避免OOM?
(1)、针对数据库cursor没有关闭的情况,如果查询数据量少是不会造成内存溢出的,但是数据量太大容易造成OOM,所以用完Cursor后应该手动调用close方法关闭cursor。
(2)、针对adapter没有复用convertView的情况,除了要在getView方法里边对convertView进行判断后复用,还应该使用ViewHolder类来保存通过findViewById获取的子控件地址值。
(3)、在Activity中注册了广播,但在Activity退出时没有取消注册的话可能会造成内存溢出,需要手动在相应的位置进行反注册。
(4)、不关闭输入输出流的话就相当于在内存和硬盘一直存在着连接占用着资源,当其他操作需要资源时,就会造成内存溢出。
(5)、位图在Android中占用的内存是很大的,使用后如不及时回收的话会占用大量空间,所以针对位图一般有以下几种处理:
及时的调用recycle方法来手动回收;
设置采样率,有时候我们不需要把图片完全显示出来,这时候就要按照比例来进行缩放,在我们得到采样率后就可以将图片缩小后再进行加载,节省大量内存;
使用软引用
(6)、应该尽量避免static成员变量引用资源耗费过多实例,比如Context
Context尽量使用Application Context,因为Application Context生命周期比较长,引用它不会出现内存泄漏的问题
使用WeakReference代替强引用。
(7)、非静态内部类,上下文泄漏。
25、Oom 是否可以try catch?为什么?
一般不适合这样处理。
java内存中除了显式地catch OOM之外还有更多有效的方式,比如SoftReference,WeakReference,硬盘缓存等。
如果OOM的原因不是在try中的代码,那么catch依然会抛出OOM的异常。
26、内存泄漏是什么?
内存泄漏是指当前程序不再使用到的内存时,释放内存失败而产生了无用的内存消耗。内存泄漏并不是指物理上的内存消失,这里的内存泄漏是指由程序分配的内存但是由于程序逻辑的错误而导致程序对该内存失去控制,使得内存浪费。
27、什么情况导致内存泄漏?
(1)、资源对象没有关闭导致内存泄漏,如查询数据库没有关闭cursor。
(2)、构造adapter时,没有使用convertView复用。
(3)、Bitmap对象不再使用时,未调用recycle()释放内存。
(4)、对象被生命周期长的对象引用,如Activity被静态集合引用导致Activity不能释放。
28、如何防止线程的内存泄漏?
将AsyncTask或Runnable类独立出来或使用静态内部类,这样可以避免内存泄漏。
29、内存泄露场的解决方法
(1)、在涉及使用Context时,优先考虑Application Context。
(2)、对于需要在静态内部类中使用非静态外部成员变量(如:Context、View),可以在静态内部类中使用弱引用来引用外部类的变量来避免内存泄漏。
(3)、对于不再需要使用的对象,显示的将其赋值为null,比如使用完Bitmap后先调用recycle(),再赋值为null.
(4)、保持对对象生命周期的敏感,特别注意单例、静态对象、全局性集合等的生命周期。
(5)、对于生命周期比Activity长的内部类对象,并且内部类中使用了外部类的成员变量,可以这样做避免内存泄漏:将内部类改为静态内部类;静态内部类中使用弱引用来引用外部类的成员变量。
30、内存泄漏和内存溢出区别?
内存泄漏的堆积就会导致内存溢出。
内存泄漏是指申请内存后无法释放已申请的内存空间,内存溢出是没有足够的内存供申请者使用。
31、LruCache默认缓存大小
手机内存的1/8
32、ContentProvider的权限管理(解答:读写分离,权限控制-精确到表级,URL控制)
文章图片
文章图片
33、如何通过广播拦截和abort一条短信?
https://blog.csdn.net/ljw124213/article/details/50492449
34、广播是否可以请求网络?
子线程可以,主线程超过10s引起anr
35、广播引起anr的时间限制是多少?
10s
36、计算一个view的嵌套层级
view.getParent()递归就可以就算嵌套层级。
37、Activity栈
Activity栈记录Activity的打开顺序,先进后出。
38、Android线程有没有上限?
其实这个是没有上限的,因为资源都是限制在这个进程中,无论开多少线程都是这么多的资源。至于开多少,完全取决于自己,合理开线程,不卡就行。
39、线程池有没有上限?
有,跟内存挂钩。
40、ListView重用的是什么?
ListView重用的是View
41、Android为什么引入Parcelable?
在内存使用上Parcelable比Serializable性能高。
42、有没有尝试简化Parcelable的使用?
as插件简化Parcelable使用。
(四)开发中常见的一些问题
1、ListView 中图片错位的问题是如何产生的?
如果只是简单的展示list中的数据,而没用convertView的复用机制和异步操作,就不会产生图片错位的问题;重用但没有异步,也不会出现这个问题,但程序会很卡。
图片错位就是因为convertView复用,同时异步加载图片造成的。
2、混合开发有了解吗?
混合开发的APP就是在app内部内嵌一个轻量级的浏览器,一部分原生的功能改为HTML5开发,这部分功能不仅能够在app不升级的情况下动态更新,且可以在Android和IOS上运行,让用户体验更好又可以节省开发的资源。
3、知道哪些混合开发的方式?说出它们的优缺点和各自使用场景?(解答:比如:RN,weex,H5,小程序,WPA等。做Android的了解一些前端js等还是很有好处的);
4、屏幕适配的处理技巧都有哪些?
布局尽量使用相对布局与线性布局
根据不同的分辨率的手机,提供不同的资源
限制横竖屏切换。
5、服务器只提供数据接收接口,在多线程或多进程条件下,如何保证数据的有序到达?
(1)、有序,多线程需要使用同步,多线程要使用进程通信保障数据传输的顺序。
(2)、到达,使用TCP可靠传输,服务器返回传输成功后才能传输下一个。
(3)、要在传输包中加入顺序标识。
6、动态布局的理解
动态加载布局有三种方式
文章图片
第一种方式内部调用的是第二种方式,第二种方式内部调用的是第三种方式。
第三种方式分析:
参数一:要加载的布局文件。
参数二:父布局容器。
参数三:false表示不把布局文件添加到容器中,true表示把布局文件添加到容器中。
如果参数三设置了false,但添加了下面的代码,表示和true一样,都可以把布局添加到容器中。
文章图片
7、怎么去除重复代码?
(1)、对于Activity或者Fragment,抽取基类BaseActivity,BaseFragment,在基类中抽取一些所有子类都需要的方法,比如:initView、initListener、initData、initStatusBarColors、startActivity、showToast、checkNetConnected等方法。
(2)、对于xml布局文件,在多个页面中同时出现的、可以重复利用的,就单独抽出来,用include引入,比如:标题栏,下一步按钮,等等一些可以抽取出来的公共部分。
(3)、对于资源文件的引用,比如文字的text、文字大小textSize、文字颜色textColor,全部采用引用,不要全部写死到布局中,对于文字text一律写到string中、对于文字大小,一律写入dimens中,对于文字颜色,一律写入到color中,然后统一引入xml布局文件中。
8、画出 Android 的大体架构图
文章图片
9、Recycleview和ListView的区别
(1)、ViewHolder是用来保存视图引用的类,无论是ListView还是RecyclerView。
在ListView中,ViewHolder需要自定义,使用ViewHolder的时候,每次getView时,都会调用findViewById,所以会造成卡顿。
RecyclerView使用RecyclerView.ViewHolder,解决了ListView的卡顿问题
(2)、ListView只能在垂直方向滑动
RecyclerView可以水平和竖直方向滑动
可以布局交叉网格风格的列表,如瀑布流
支持网格风格的列表。
(3)、RecyclerView增加了View动画
(4)、ListView通过AdapterView.OnItemClickListener接口来探测点击事件。
RecyclerView则通过RecyclerView.OnItemTouchListener接口来探测触摸事件。
https://blog.csdn.net/kimi985566/article/details/79839692
10、ListView图片加载错乱的原理和解决方案
ListView图片加载错乱是因为异步请求和convertView复用造成的。
解决方案:
对imageView设置tag,并预设一张图片。
11、动态权限适配方案,权限组的概念
对于低于M版本的Android系统,没有动态权限的申请问题,动态权限的申请流程对于低于M版本的android系统也不再适用。所以适配方案,首先要考虑低于M版本的Android系统,因此对于低于M版本的Android系统,在检查权限时,直接返回true;对于高于M版本的系统,可以将动态权限申请进行一次封装。
12、Android系统为什么会设计ContentProvider?
Android设计ContentProvider主要是为了实现跨进程通信。
为了应用程序之间交换数据,Android提供了ContentProvider,ContentProvider是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序就可以通过提供ContentProvider来实现,其他应用程序就可以通过ContentProvider来操作ContentProvider暴露出来的数据。
13、下拉状态栏是不是影响activity的生命周期
不会影响Activity的生命周期。
14、如果在onStop的时候做了网络请求,onResume的时候怎么恢复?
stop的时候被暂停,onStart的时候重新检测恢复请求即可。
如果是恢复页面请求后的页面数据,分两种,一、Activity已经销毁,那么使用saveInstanceState存储数据,onRestoreInstanceState()恢复数据;二,Activity没有销毁,那就不需要恢复。
15、Bitmap 使用时候注意什么?
(1)、要使用合适的图片规格(bitmap类型)
(2)、降低采样率
(3)、复用内存。
(4)、及时回收
(5)、压缩图片
(6)、尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都会通过java层调用createBitmap来完成,需要消耗更多的内存,可以通过BitmapFactory.decodeStream方法,创建出一个Bitmap,再将其设置成ImageView的source。
https://www.jianshu.com/p/fbf5a310788c
16、Bitmap的recycler()
Android有自己的垃圾回收机制,如果只使用了少量的图片,回收与否关系不大。可是若有大量的bitmap需要垃圾回收,那么垃圾回收的次数过于频繁,会造成系统资源负荷。所以还是自己recycler()比较好。
一定要注意ImageView的图片来源,然后进行相应的recycler
17、Android中开启摄像头的主要步骤
一共有两种方式可以使用Android中的摄像头
(1)、调用Android系统现有的摄像头程序。
(2)、直接使用Android系统提供的摄像头API。
文章图片
启动安装在手机上的摄像头应用程序。
文章图片
使用静态方法通过Camera.open()方法初始化相机对象。
18、ViewPager使用细节,如何设置成每次只初始化当前的Fragment,其他的不初始化?
每次只初始化一个页面的时候,就要注意了,需要采用懒加载的方式,因为在页面进入前台的时候,是会调用setUserVisiableHint()这个方法的,通过这个方法,我们可以获得当前页面是否对用户可见,并在对用户可见的时候进行初始化,这时还需要注意一点,setUserVisiableHint()这个方法的调用并不保证View等需要的东西是否已经初始化成功,所以还需要再判断一下。
19、点击事件被拦截,但是想传到下面的View,如何操作?
在父控件中加入请求父控件不拦截子控件的触摸事件,自定义重写子控件的dispatchTouchView();
文章图片
就可以阻止父控件对子控件点击事件的拦截,可以为子控件单独设置点击事件的响应。
20、微信主页面的实现方式
fragment嵌套。
21、微信上消息小红点的原理
可以是UI设计是切出的带有小红点的图,也可以自定义RadioButton绘制小红点。
22、CAS介绍(这是阿里巴巴的面试题,我不是很了解,可以参考博客: CAS简介)
文章图片
(1)、访问服务:SSO客户端发送请求访问应用系统提供的服务资源。
(2)、重定向认证:SSO客户端会重定向用户请求到SSO服务器
(3)、用户验证:验证用户身份
(4)、生成票据:SSO服务器会产生一个随机的Service Ticket
(5)、验证票据:SSO服务器验证票据Service Ticket的合法性,验证通过后,允许客户端访问服务。
(6)、传输用户信息:SSO服务器验证票据通过后,传输用户认证结果信息给客户端。
附;AndroidAPP开发框架技术体系大纲;
推荐阅读
- PMSJ寻平面设计师之现代(Hyundai)
- android第三方框架(五)ButterKnife
- 杜月笙的口才
- Android中的AES加密-下
- 带有Hilt的Android上的依赖注入
- Linux下面如何查看tomcat已经使用多少线程
- 皮夹克
- android|android studio中ndk的使用
- 解读《摩根集团》(1)
- 绘本与写作