Android - Android 面试题集 -- Android 部分答案

时间:2021-05-05 14:41:52

2.1 Activity
1.Activity是什么?
Activity是Android的四大组件之一。是用户操作的可视化界面;它为用户提供了一个完成操作指令的窗口。
当我们创建完毕Activity之后,需要调用setContentView()方法来完成界面的显示;以此来为用户提供交互的入口。


2.典型情况下的Activity生命周期?
Activity启动–>onCreate()–>onStart()–>onResume()
点击home键回到桌面–>onPause()–>onStop()
再次回到原Activity时–>onRestart()–>onStart()–>onResume()
退出当前Activity时–>onPause()–>onStop()–>onDestroy()


3.异常情况下的Activity的生命周期 & 数据如何保存和恢复?
在onStop之前调用onSaveInstanceState保存当前Activity状态,当Activity被重新创建后,系统调用
onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象
作为参数传递给onRestoreInstanceState和onCreate方法
onRestoreInstanceState的调用时机发生在onStart之后


4.从Activity A跳转到Activity B之后,然后再点击back键之后,它们的生命周期调用流程是什么?
从Activity A跳转到Activity B
Activity A -> onPause()
Activity B -> onCreate()
Activity B -> onStart()
Activity B -> onResume()
Activity A -> onStop()

点击back键
Activity B -> onPause()
Activity A -> onRestart()
Activity A -> onStart()
Activity A -> onResume()
Activity B -> onStop()
Activity B -> onDestroy()


5.如何统计Activity的工作时间?
Activity开始工作的起点是onResume()而工作的停止点为onPause(),
因此当每次Activity调用onResume()的时候记录一个时间a,每次调用onPause()的时候再记录一个时间b,
那么由b-a可得当次Activity工作的时间。


6.给我说说Activity的启动模式 & 使用场景。
系统默认的启动模式:standard
系统的默认模式,每次启动一个Activity都会重新创建一个新的实例
栈顶复用模式:singleTop
如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),
否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。
使用场景如新闻类或者阅读类App的内容页面。
栈内复用模式:singleTask
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。
重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,
并且会清空主界面上面的其他页面。
单实例模式:singleInstance
在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。
一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例
( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。
使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,
比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。


7.如何在任意位置关掉应用所有Activity & 如何在任意位置关掉指定的Activity?
封装一个类,成员变量有一个List集合,当Activity执行onCreate()方法时将当前的Activity实例加入,
遍历这个List且逐一调用finish()即可
给每个启动的Activity一个tag,根据这个tag和集合可达到在任意位置关闭指定Activity的效果。


8.Activity的启动流程(从源码角度解析)?
app启动的过程有两种情况,第一种是从桌面launcher上点击相应的应用图标,
第二种是在activity中通过调用startActivity来启动一个新的activity。
我们创建一个新的项目,默认的根activity都是MainActivity,而所有的activity都是保存在堆栈中的,
我们启动一个新的activity就会放在上一个activity上面,而我们从桌面点击应用图标的时候,由于launcher本身也是一个应用,
当我们点击图标的时候,系统就会调用startActivitySately(),一般情况下,我们所启动的activity的相关信息都会保存在intent中,
比如action,category等等。我们在安装这个应用的时候,系统也会启动一个PackaManagerService的管理服务,
这个管理服务会对AndroidManifest.xml文件进行解析,从而得到应用程序中的相关信息,比如service,activity,Broadcast等等,然后获得相关组件的信息。
当我们点击应用图标的时候,就会调用startActivitySately()方法,而这个方法内部则是调用startActivty(),
而startActivity()方法最终还是会调用startActivityForResult()这个方法。
因为startActivityForResult()方法是有返回结果的,所以系统就直接给一个-1,就表示不需要结果返回了。
而startActivityForResult()这个方法实际是通过Instrumentation类中的execStartActivity()方法来启动activity,
Instrumentation这个类主要作用就是监控程序和系统之间的交互。而在这个execStartActivity()方法中会获取ActivityManagerService的代理对象,
通过这个代理对象进行启动activity。启动会就会调用一个checkStartActivityResult()方法,如果说没有在配置清单中配置有这个组件,就会在这个方法中抛出异常了。
当然最后是调用的是Application.scheduleLaunchActivity()进行启动activity,而这个方法中通过获取得到一个ActivityClientRecord对象,
而这个ActivityClientRecord通过handler来进行消息的发送,系统内部会将每一个activity组件使用ActivityClientRecord对象来进行描述,
而ActivityClientRecord对象中保存有一个LoaderApk对象,通过这个对象调用handleLaunchActivity来启动activity组件,
而页面的生命周期方法也就是在这个方法中进行调用。


9.启动一个其它应用的Activity的生命周期分析。
同4


10.Activity任务栈是什么?在项目中有用到它吗?说给我听听
-android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。
-我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
-在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。
-需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。

 



11.什么情况下Activity不走onDestory?
当 Activity 被另外一个 Activity 覆盖、失去焦点并不可见时处于 Stoped 状态。
9.0的时候如果强行终止activity,那么也不会执行onDestory


12.什么情况下Activity会单独执行onPause?
同11


13.a->b->c界面,其中b是SingleInstance的,那么c界面点back返回a界面,为什么?
SingleInstance 这是一种加强的singleTask模式,它除了具有singleTask模式所有的特性外,还加强了一点,那就是具有此种模式的Activity只能单独位于一个任务栈中,换句话说,比如Activity A是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了


14.如果一个Activity弹出一个Dialog,那么这个Acitvity会回调哪些生命周期函数呢?
是否弹出 Dialog,并不影响 Activity 的生命周期,所以这时和正常启动时 Activity 的生命回调方法一致: onCreate() -> onStart() -> onResume()。


15.Activity之间如何通信 & Activity和Fragment之间通信 & Activity和Service之间通信?
1.Activity->Activity
[1]Intent/Bundle
这种方式多用于Activity之间传递数据
[2]类静态变量
在Activity内部定义静态的变量,这种方式见于少量的数据通信,如果数据过多,还是使用第一种方式
[3]全局变量
创建一个类,里面定义一批静态变量,Activity之间通信都可以访问这个类里面的静态变量,这就是全局变量。

2.Activity->Service
[1]绑定服务的方式,利用ServiceConnection这个接口
[2]Intent
这种方式很简单,我们在启动和停止Service时所调用的方法都需要传入一个Intent实例对象,通过这个传入的Intent对象,我们就可以与Service进行通信。
[3]CallBack + Handler,监听服务的进程变化

3.Activity->Fragment
[1]Bundle
在创建Fragment实例的时候,调用方法setArguments将一个Bundle对象传递给Fragment,然后在Fragment中先去判断是否和当前Activity绑定上了,如果绑定上了,就可以拿出这个Bundle中的数据
[2]直接进行方法调用
在Activity里通过Fragment的引用,可以直接调用Framgent中的定义的任何方法。


16.说说Activity横竖屏切换的生命周期。
 onPause
 onSaveInstanceState //这里可以用来横竖屏切换的保存数据
 onStop
 onDestroy
 onCreate
 onStart
 onRestoreInstanceState//这里可以用来横竖屏切换的恢复数据
 onResume


17.前台切换到后台,然后在回到前台时Activity的生命周期。
点击home键回到桌面–>onPause()–>onStop()
再次回到原Activity时–>onRestart()–>onStart()–>onResume()


18.下拉状态栏时Activity的生命周期?
首先,通知栏下拉一点点,符合一般描述中“Activity被部分遮挡”——onPause()
然后,通知栏完全落下之后,“Activity被全部遮挡”——onStop()


19.Activity与Fragment的生命周期比较?
onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume();
Fragment变为不可见状态(锁屏、回到桌面、被Activity完全覆盖):onPause()->onSaveInstanceState()->onStop();
Fragment变为部分可见状态(打开Dialog样式的Activity):onPause()->onSaveInstanceState();
Fragment由不可见变为活动状态:onStart()->OnResume();
Fragment由部分可见变为活动状态:onResume();
退出应用:onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()
Fragment被回收又重新创建:被回收执行onPause()->onSaveInstanceState()->onStop()->onDestroyView()->onDestroy()->onDetach(),重新创建执行onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->setUserVisibleHint();
横竖屏切换:与Fragment被回收又重新创建一样。


20.了解哪些Activity常用的标记位Flags?
1.Intent.FLAG_ACTIVITY_NEW_TASK,是为Activity指定“singleTask”启动模式
2.Intent.FLAG_ACTIVITY_SINGLE_TOP,是为Activity指定“singleTop”启动模式
3.FLAG_ACTIVITY_CLEAR_TOP,如果跟singleTask启动模式一起出现,如果被启动的Activity已经存在实例,则onNewIntent方法会被回调,如果被启动的Activity采用standard模式启动,那么连同它跟它之上的Activity都要出栈,并且创建新的实例放入栈顶。
4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS,新的Activity不会在最近启动的Activity的列表中保存。等同于指定属性android:excludeFromRecents="true"


21.谈谈隐式启动和显示启动Activity的方式?
显式启动:直接指定要跳转的Activity类名,不用过滤,效率高,适用于同一个应用中的不同Activity跳转
隐式启动:需要过滤,相对耗时,但可以找到所有之匹配的应用。适用于不同应用之间的Activity跳转。
隐式启动会找到所匹配到的应用,并提示用户选择打开方式,如果有多个组件被匹配成功,就会以对话框列表的方式让用户进行选择。


22.Activity用Intent传递数据和Bundle传递数据的区别?为什么不用HashMap呢?
要把值通过A经过B传给C
如果用Intent的话 A-B先写一遍 再在B中都取出来 然后在把值塞到Intent中 再跳到C 累吗?
如果我在A中用了 Bundle 的话  我把Bundle传给B 在B中再转传到C  C就可以直接去了
这样的话 还有一个好处 就是在B中 还可以给Bundle对象添加新的 key - value 同样可以在C中取出来

为什么不用HashMap呢?
Bundle内部是由ArrayMap实现的,ArrayMap的内部实现是两个数组,一个int数组是存储对象数据对应下标,一个对象数组保存key和value,内部使用二分法对key进行排序,所以在添加、删除、查找数据的时候,都会使用二分法查找,只适合于小数据量操作,如果在数据量比较大的情况下,那么它的性能将退化。而HashMap内部则是数组+链表结构,所以在数据量较少的时候,HashMap的Entry Array比ArrayMap占用更多的内存。因为使用Bundle的场景大多数为小数据量
在Android中如果使用Intent来携带数据的话,需要数据是基本类型或者是可序列化类型,HashMap使用Serializable进行序列化,而Bundle则是使用Parcelable进行序列化。而在Android平台中,更推荐使用Parcelable实现序列化,虽然写法复杂,但是开销更小,所以为了更加快速的进行数据的序列化和反序列化,系统封装了Bundle类,方便我们进行数据的传输。


23.在隐式启动中Intent可以设置多个action,多个category吗 & 顺便讲讲它们的匹配规则?
一个Intent对象中最多只能包括一个Action属性,但可以包含多个Category属性


24.Activity可以设置为对话框的形式吗?
在mainifest中对应的activity上配置如下的代码,即可让activity以对话框的方式表现出来
< android:theme="@android:style/Theme.Dialog">


25.如何给Activity设置进入和退出的动画?
一种是直接在代码中设置,这需要使用到Activity的overridePendingTransition方法;
另一种是通过自定义Activity的主题来实现。


26.Activity使用Intent传递数据是否有限制 & 如果传递一个复杂的对象,例如一个复杂的控件对象应该怎么做?
1 传512K以下的数据的数据可以正常传递。
2 传512K~1024K的数据会出错,闪退。
3 传1024K以上的数据会报错:TransactionTooLargeException。
4 考虑到Intent还包括要启动的Activity等信息,实际可以传的数据略小于512K

如果传递一个复杂的对象,例如一个复杂的控件对象应该怎么做?
1)将对象转换为Json字符串
2)使用Serializable,Parcelable序列化对象
1.Serializable实现:
    ①业务Bean实现:Serializable接口,写上getter和setter方法
    ②Intent通过调用putExtra(String name, Serializable value)传入对象实例 当然对象有多个的话多个的话,我们也可以先Bundle.putSerializable(x,x);
    ③新Activity调用getSerializableExtra()方法获得对象实例: eg:Product pd = (Product) getIntent().getSerializableExtra("Product");
    ④调用对象get方法获得相应参数
2.Parcelable实现:
一般流程:
    ①业务Bean继承Parcelable接口,重写writeToParcel方法,将你的对象序列化为一个Parcel对象;
    ②重写describeContents方法,内容接口描述,默认返回0就可以
    ③实例化静态内部对象CREATOR实现接口Parcelable.Creator
    ④同样式通过Intent的putExtra()方法传入对象实例,当然多个对象的话,我们可以先 放到Bundle里Bundle.putParcelable(x,x),再Intent.putExtras()即可
3.使用数据库

 

2.2 BroadcastReceiver
1.广播是什么?
它是一种广泛运用在应用程序之间传输信息的机制,Android中我们发送广播内容是一个Intent,这个Intent中可以携带我们要发送的数据。


2.广播的注册方式有哪些?
1 静态注册:创建一个广播接收器类,广播接收器在AndroidManifest.xml文件中注册
2 动态注册:新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法就行了


3.广播的分类 & 特性 & 使用场景?
3.1 无序广播
  context.sendBroadcast(Intent)方法发送的广播,不可被拦截,当然发送的数据,接收者是不能进行修改的。
3.2 有序广播
context.sendOrderBroadcast(Intent)方法发送的广播,可被拦截,而且接收者是可以修改其中要发送的数据,修改和添加都是可以的,这就意味着优先接收者对数据修改之后,下一个接收者接受的数据是上一个接收者已经修改了的,这必须明白。
3.3 本地广播
  localBroadcastManager.sendBroadcast(Intent),只在app内传播。


4.说说系统广播和本地广播的原理 & 区别 & 使用场景。
4.1 系统广播的源码角度分析
  a.自定义广播接收者BroadcastReceiver,并且重写onReceiver()方法。
  b.通过Binder机制向AMS(Activity Manager Service)进行注册。
  c.广播发送者通过Binder机制向AMS发送广播。
  d.AMS查找符合条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到相应的BroadcastReceiver(一般情况下是Activity)的消息队列中。
  e.消息循环执行拿到此广播,回调BroadcastReceiver中的onReceiver()方法。
4.2 本地广播的源码角度分析
相比于系统广播而言,本地广播更加安全,更加高效,以下是本地广播的特点以及内部的实现机制:
特点:
  a.使用它发送的广播将只在自身app内传播,因此你不必担心泄漏隐私的数据。
  b.其他app无法对你的app发送该广播,因此你的app根本不可能收到非自身app发送的该广播,因此你不必担心有安全漏洞可以利用。
  c.比系统广播更加高效。


5.有两个应用注册了一样的广播,一个是静态,一个是动态,连优先级也一样,那么当广播从系统发出来后,哪个应用先接收到广播?
动态注册的接收者会先执行


2.3 ContentProvider
1.什么是内容提供者?
(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能


2.说说如何创建自己应用的内容提供者 & 使用场景。
新建一个类去继承ContentProvider类的方式来创建一个自己的内容提供器。ContentProvider类有6个抽象方法,我们在使用子类继承它的时候,需要将这6个方法全部重写。


3.说说ContentProvider的原理。
一种进程间通信的方式,其实它原理核心就是Binder。


4.ContentProvider,ContentResolver,ContentObserver之间的关系?
ContentProvider——内容提供者, 在android中的作用是对外共享数据,也就是说你可以通过
ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。
ContentResolver——内容解析者, 其作用是按照一定规则访问内容提供者的数据(其实就是调用内容提供者自定义的接口来操作它的数据)。 ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它


5.说说ContentProvider的权限管理。
android:grantUriPermssions:临时许可标志。
android:permission:Provider读写权限。
android:readPermission:Provider的读权限。
android:writePermission:Provider的写权限。
android:enabled:标记允许系统启动Provider。
android:exported:标记允许其他应用程序使用这个Provider。
android:multiProcess:标记允许系统启动Provider相同的进程中调用客户端。

 

2.4 Service
1.什么是Service?
Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的组件。它运行于UI线程,因此不能进行耗时的操作。


2.说说Service的生命周期。
bindService:onCreate()-onBind()-unBind()-onDestroy()
这种方式进行启动service好处是更加便利activity中操作service,通过ServiceConnection来获取service中内部类的类对象,然后通过这个类对象就可以调用类中的方法
startService:onCreate()-onStartCommon()-onDestroy()
当我们通过startService被调用以后,多次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被多次调用


3.Service和Thread的区别?
Service的运行是在UI线程当中的,是绝对绝对不能进行耗时操作的,而Thread开启的子线程则可以进行耗时操作,但是Thread开启的子线程是不能直接对UI进行操作的,否则极有可能发生直接让程序崩掉,这就是它们的区别。


4.Android 5.0以上的隐式启动问题及其解决方案。
1 将隐式启动转换为显式启动,兼容编译sdk5.0以后版本
2 直接写上包名以及标志
3 判断应用是否安装


5.给我说说Service保活方案
1)onStartCommand方法,返回START_STICKY
2)提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
3)提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
复制代码
1.前台进程( FOREGROUND_APP)
2.可视进程(VISIBLE_APP )
3.次要服务进程(SECONDARY_SERVER )
4.后台进程 (HIDDEN_APP)
5.内容供应节点(CONTENT_PROVIDER)
6.空进程(EMPTY_APP)
4)onDestroy方法里重启service
5)Application加上Persistent属性


6.IntentService是什么 & 原理 & 使用场景 & 和Service的区别。
IntentService是继承处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentServiced的方式和启动传统的Service一样,同时,当任务执行完成后,IntentService会自动停止,而不需要我们手动去控制或stopSelf()。
a.它本质是一种特殊的Service,继承自Service并且本身就是一个抽象类。
b.它内部是由HandlerThread和Handler实现异步操作。


7.创建一个独立进程的Service应该怎样做?
创建远程服务
1)定义AIDL接口
2)新建Remote Service
3)在AndroidManifest.xml中对Remote Service进行配置


8.Service和Activity之间如何通信?
1、Intent传值,onStartCommand()接收。
2、通过onBind()获取Service实例,然后再调用Binder中的相关方法。
3、通过回调函数达到侦听Service中数据变化。


9.说说你了解的系统Service。
https://blog.csdn.net/geyunfei_/article/details/78851024


10.谈谈你对ActivityManagerService的理解。
从系统运行的角度看,AmS可以分为Client端和Service端:Client端运行在各个app进程,app进程实现了具体的Activity,Service等,告诉系统我有那些Activity,Service等,并且调用系统接口来完成显示;Service端运行在SystemServer进程,是系统级别的ActivityManagerService的具体实现,其响应Client端的系统调用请求,并且管理Client端各个app进程的生命周期。
https://www.cnblogs.com/xingchenkn/p/3637137.html


11.在Activtiy中创建一个Thread和在一个Service中创建一个Thread的区别?
Activtiy中的线程是前台线程,它的生命周期往往是随着Activity的,Activity销毁的时候,那个线程也应该被销毁,否则就会出现内存泄漏现象。而Service中开启的线程,它是工作在后台的,一般来讲,后台线程的生存期是比较长的。

2.5 Handler
1.子线程一定不能更新UI吗?
是否有些控件支持在子线程更新UI呢?比如:SurfaceViw
在Activity的onResume()生命周期函数之前是可以在子线程中更新UI的。


2.给我说说Handler的原理
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
Handler是可以通过发送和处理Message和Runnable对象来关联相应线程的MessageQueue。通常我们认为它是一种异步机制。
a.可以让对应的Message和Runnable在未来的某个时间点进行相应的处理。
b.让自己想要的耗时操作在子线程中完成,让更新UI的操作在主线程中完成,而子线程与主线程之间的通信就是靠Handler来完成。


3.Handler导致的内存泄露你是如何解决的?
Handler导致内存泄漏的原因是:非静态内部类持有外部类的引用,导致外部类在没有被使用的时候,迟迟不能被回收,从而导致内存泄漏。即非静态Handler内部类持有外部Activity的引用,导致外部Activity退出/销毁的时候,它迟迟不能被回收,最终导致Activity的内存泄漏。 解决方法:将Handler类声明为静态,如果Handler需要访问外部类Activity的成员变量或者成员方法,可以用弱引用的方式解决。


4.如何使用Handler让子线程和子线程通信?
在ThreadA中准备一个Looper,也就是消息轮询大管家,然后准备发送消息的Handler,准备发送消息的Handler很容易理解,那就是在ThreadA中生成一个Handler对象即可,
那么准备Looper怎么做呢?在ThreadA中调用Looper.prepare(),然后再调用Looper.loop()即可


5.你能给我说说Handler的设计原理?

 

6.HandlerThread是什么 & 原理 & 使用场景?
a.HandlerThread本质上是一个线程类,它继承了Thread。
b.HandlerThread有自己内部的Looper对象,可以进行Looper循环。
c.通过获取HandlerThread的Looper对象传递给Handler对象,可以在handlerMessage方法中执行异步任务。
d.优点是不会有堵塞,减少对性能的消耗,缺点是不能进行多任务的处理,需要等待进行处理,处理效率较低。
e.与线程池注重并发不同,HandlerThread是一个串行队列,HandlerThread背后只有一个线程


7.IdleHandler是什么?
IdleHandler 可以用来提升性能,主要用在我们希望能够在当前线程消息队列空闲时做些事情(譬如 UI 线程在显示完成后,如果线程空闲我们就可以提前准备其他内容)的情况下,不过最好不要做耗时操作。


8.一个线程能否创建多个Handler,Handler和Looper之间的对应关系?
一个线程可以有多个Handler,但是一个线程只能有一个Looper,一个MessageQueue。因此它们之间的关系是一个线程只能有一个Looper,一个MessageQueue,多个Handler。


9.为什么Android系统不建议子线程访问UI?
UI控件不是线程安全的,如果多线程并发访问UI控件可能会出现不可预期的状态
那为什么系统不对UI控件的访问加上锁机制呢?
加上锁机制会让UI访问的逻辑变得复杂; 锁机制会降低UI访问的效率,因为锁机制会阻塞某些线程的执行;


10.Looper死循环为什么不会导致应用卡死?
ActivityThread的main方法主要就是做消息循环,一旦退出消息循环,那么你的应用也就退出了。


11.使用Handler的postDealy后消息队列有什么变化?
https://blog.csdn.net/qingtiantianqing/article/details/72783952


12.可以在子线程直接new一个Handler出来吗?
1(需先在该线程中手动开启Looper(Looper.prepare()-->Looper.loop()),然后将其绑定到Handler对象上
2(通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上

13.Message对象创建的方式有哪些 & 区别?
https://blog.csdn.net/dfskhgalshgkajghljgh/article/details/52672115