安卓面试

Android 面试整理

2017-03-14  本文已影响28人  阳光下的狐狸
自我介绍

我叫王少健,平时喜欢旅游,一方面作为兴趣爱好的培养,同时也是自我释压的方式;和平友爱是我的交流方式,做人不失小幽默。我比较喜欢专研新技术,有较扎实的Java和Android方面的基础知识。在上一年工作,因为是我个人独立开发的程序,在公司中我学到了很多,主要是在学习中找到了快乐,不断在沉淀自己地小天地。感到在工作中的我很充实;希望通过自身不懈的努力与执着的追求,在IT领域中有所成就.

说一下上一个项目中的主要技术、

使用http和ftp实现与服务器交互,并且下载文件。
使用的University_Image_Loader实现的图片的三级缓存(看一下源码)
通过广播实现了fragment之间的沟通。

主线程和工作线程的区别?

主线程和工作线程的关系如下
1.主线程结束前向工作线程发送结束消息,通知工作线程退出。
2.主线程立即进入等待工作线程死亡状态WaitforSingleObject,WaitforMultipleObjects....
3.工作线程收到退出消息,退出(因为工作在一个大的WairforSingleObject(退出通知)中)。
4.主线程等烦了(等待超时),直接杀死工作线程。
5.程序退出。
可以说一下:主线程无法更新UI,造成线程阻塞。子线程即工作线程

IntentService与Service的区别

Service主要用于后台服务 当应用程序被挂到后台的时候,为了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。这时需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行你的耗时操作。
IntentService:异步处理服务,新开一个线程:handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务。
IntentService有以下特点:
(1) 它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。
(2) 创建了一个工作队列,来逐个发送intent给onHandleIntent()。
(3) 不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。
(4) 默认实现的onBind()返回null
(5) 默认实现的onStartCommand()的目的是将intent插入到工作队列中

RxJava 的适用场景和使用方式
  1. 与 Retrofit 的结合
  2. 各种异步操作
    例如数据库的读写、大图片的载入、文件压缩/解压等各种需要放在后台工作的耗时操作,都可以用 RxJava 来实现
View的事件分发

ViewGroup的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。
View的相关事件只有两个:dispatchTouchEvent、onTouchEvent。
1、整个View的事件转发流程是:
View.dispatchTouchEvent->View.setOnTouchListener->View.onTouchEvent
在dispatchTouchEvent中会进行OnTouchListener的判断,如果OnTouchListener不为null且返回true,则表示事件被消费,onTouchEvent不会被执行;否则执行onTouchEvent。
1、整个ViewGroup的事件转发流程是:
可以看到大体的事件流程为:
MyLinearLayout的dispatchTouchEvent -> MyLinearLayout的onInterceptTouchEvent -> MyButton的dispatchTouchEvent ->Mybutton的onTouchEvent
1、如果ViewGroup找到了能够处理该事件的View,则直接交给子View处理,自己的onTouchEvent不会被触发;
2、可以通过复写onInterceptTouchEvent(ev)方法,拦截子View的事件(即return true),把事件交给自己处理,则会执行自己对应的onTouchEvent方法
3、子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截;
好了,那么实际应用中能解决哪些问题呢?
比如你需要写一个类似slidingmenu的左侧隐藏menu,主Activity上有个Button、ListView或者任何可以响应点击的View,你在当前View上死命的滑动,菜单栏也出不来;因为MOVE事件被子View处理了~ 你需要这么做:在ViewGroup的dispatchTouchEvent中判断用户是不是想显示菜单,如果是,则在onInterceptTouchEvent(ev)拦截子View的事件;自己进行处理,这样自己的onTouchEvent就可以顺利展现出菜单栏了~~

以下摘自http://www.toutiao.com/i6398007879990772226/

1. Activity建立在哪些窗口组件之上?顺带涉及View的事件传递问题。

没读懂问题,=。=不知道是不是问Activity的UI结构,如果是可以参考这篇文章。


8862185a17af456f29a005bb4a06b1d3_18f8000dd7b7d7d407bd.jpg

对于View的事件传递,则可以从 Activity --> ViewGroup --> ...... --> Activity
的** U型 **消费结构去说。

2. 什么情况下,Activity的onNewInstent方法会执行?Activity的启动模式相关。

当此Activity的实例已经存在,并且此时的启动模式为SingleTask和SingleInstance,另外当这个实例位于栈顶且启动模式为SingleTop时也会触发onNewInstent。

3. Activity A使用startForResult启动Activity B,B什么都不做并返回A,A中的onActivityResult回调是否会执行?

startActivity方法,最终都是调用startActivityForResult方法。默认的requestCode = -1 resultCode = RESULT_CANCELED = 0,当你的requestCode != -1时,onActivityResult一定会被调用。

4. Fragment能否不依赖于Activity存在?简析一下Fragment的栈管理。

Fragment不能独立存在,它必须嵌入到activity中,而且Fragment的生命周期直接受所在的activity的影响。
// Create new fragment and transaction Fragment newFragment = new ExampleFragment;
FragmentTransaction transaction = getFragmentManager.beginTransaction;
// Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null);
// Commit the transaction transaction.commit;
transaction只是记录了从一个状态到另一个状态的变化过程,即比如从FragmentA替换到FragmentB的过程,当通过函数transaction.addToBackStack(null)将这个事务添加到回退栈,则会记录这个事务的状态变化过程,如从FragmentA —>FragmentB,当用户点击手机回退键时,因为transaction的状态变化过程被保存,则可以将事务的状态变化过程还原,即将FragmentB —> FragmentA.
添加到回退栈的函数:transaction.addToBackStack(null);

5. 能否将一个Activity放到系统的最近任务列表里,独立于宿主app任务卡之外?

我印象中是可以做到了,平时没用到,知道的同学请@我,谢谢!

6. 对于同一个Service,在被start启动之后还能不能被bind?


服务基本上分为两种形式:
启动
当应用组件(如 Activity)通过调用 startService 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。 操作完成后,服务会自行停止运行。
绑定
当应用组件通过调用 bindService 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
虽然本文档是分开概括讨论这两种服务,但是您的服务可以同时以这两种方式运行,也就是说,它既可以是启动服务(以无限期运行),也允许绑定。问题只是在于您是否实现了一组回调方法:onStartCommand(允许组件启动服务)和 onBind(允许绑定服务)。
来自官方文档

7. Service有哪些派生类?这些派生类的使用场景是什么?

这个问题不知道问的具体是什么,如果是要 IntentService
那么可以参考官方文档的解释与使用说明:
扩展 IntentService 类
由于大多数启动服务都不必同时处理多个请求(实际上,这种多线程情况可能很危险),因此使用 IntentService 类实现服务也许是最好的选择。
IntentService 执行以下操作:
创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand 的所有 Intent。 创建工作队列,用于将 Intent 逐一传递给 onHandleIntent 实现,这样您就永远不必担心多线程问题。 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf。 提供 onBind 的默认实现(返回 null)。 提供 onStartCommand 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent 实现。 综上所述,您只需实现 onHandleIntent 来完成客户端提供的工作即可。(不过,您还需要为服务提供小型构造函数。)

以下是 IntentService 的实现示例:
public class HelloIntentService extends IntentService { /** * A constructor is required, and must call the super IntentService(String) * constructor with a name for the worker thread. / public HelloIntentService { super("HelloIntentService"); } /* * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread.interrupt; } } }

您只需要一个构造函数和一个 onHandleIntent 实现即可。
如果您决定还重写其他回调方法(如 onCreate()、onStartCommand() 或 onDestroy()),请确保调用超类实现,以便 IntentService 能够妥善处理工作线程的生命周期。
例如,onStartCommand 必须返回默认实现(即,如何将 Intent 传递给 onHandleIntent()):
@Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show; return super.onStartCommand(intent,flags,startId); }

除 onHandleIntent 之外,您无需从中调用超类的唯一方法就是 onBind(仅当服务允许绑定时,才需要实现该方法)。

8. Service与其它组件之间的通信实现方式有哪些?

binder
broadcast
其他参见线程和进程的通信方式

9. View的post(Runnable r)方法里,r会带来一个新的线程吗?多线程相关。

不会,最终还是handler发送消息,执行在UI线程。
如下是源码和注释:
/** * <p>Causes the Runnable to be added to the message queue. * The runnable will be run on the user interface thread.</p> * * @param action The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. * * @see #postDelayed * @see #removeCallbacks */ public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.post(action); } // Postpone the runnable until we know on which thread it needs to run. // Assume that the runnable will be successfully placed after attach. getRunQueue.post(action); return true; }

10. 在非UI线程中使用Handler需要注意哪些问题?

参考:
new Thread{
public void run
//给当前线程初始化Looper
{ Looper.prepare;
//Toast初始化的时候会new Handler;
Toast.makeText(getApplicationContext,"更新UI",0).show;
无参构造默认获取当前线程的Looper,如果没有prepare过,则抛出题主描述的异常。上一句代码初始化过了,就不会出错。 Looper.loop;//这句执行,Toast排队show所依赖的Handler发出的消息就有人处理了,Toast就可以吐出来了。但是,这个Thread也阻塞这里了,因为loop是个for (;;) ... } }.start;

11. 自定义View时有哪些重要的方法,它们的作用及执行顺序是怎样的?

按照顺序:onMeasure
-->onLayout
-->onDraw
.其他的自己扩展吧。

12. 如何单独对ListView上的一个item进行更新?

更新对应view的内容
通过ViewHolder去设置值
调用一次getView方法(Google IO 推荐)

13. 简析一下大图片的加载处理。

对Bitmap的理解,然后就是压缩图片。

14. 设计师只给了一套1280*800的UI图标注,如何进行其它分辨率尺寸屏幕的适配?

名称
像素密度范围
图片大小

mdpi
120dp~160dp
48×48px

hdpi
160dp~240dp
72×72px

xhdpi
240dp~320dp
96×96px

xxhdpi
320dp~480dp
144×144px

xxxhdpi
480dp~640dp
192×192px

以 720*1080 5英寸为例:
(720^2 + 1080^2)开方=260
放在xhdpi中。
本题中同理可以算得 293,还是xhdpi中。

15. 6.0系统新权限机制的解决方案。

这个。。。没什么好说的,真正了解的很好说,不了解的话就有点绕。

? 你们精通的开源框架,问题来了

写各种精通其实是可以的,要么真牛x,如果不是很牛x那就在最后加上一条精通----精通各种被打脸

16. EventBus的机制是什么?和Handler的区别怎样?

EventBus
是采用观察者模式实现的事件订阅总线,可以用在应用程序中,组件之间,线程之间的通信,并且由于事件可以是任意类型的对象,所以使用起来更加的方便快捷。
Handler
是 Android 的消息机制,集中解决线程间通信问题。

17. RxJava的机制是什么?

RxJava是使用Java语言,以响应式编程思维来进行编程的Java类库。参考ReactiveX

18. Butterknife的机制是什么?

Java Annotation Processing技术,在Java代码编译成Java字节码的时候就已经处理了@Bind、@OnClick(ButterKnife还支持很多其他的注解)这些注解了。
Annotation processing 是javac中用于编译时扫描和解析Java注解的工具
Annotation processing是在编译阶段执行的,它的原理就是读入Java源代码,解析注解,然后生成新的Java代码。新生成的Java代码最后被编译成Java字节码,注解解析器(Annotation Processor)不能改变读入的Java 类,比如不能加入或删除Java方法。
参考:ButterKnife框架原理

19. Okhttp是基于HTTP连接还是Socket连接?

基于Http的。

Activity/Window/View三者的差别,fragment的特点

Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutInflater像剪刀,Xml配置像窗花图纸。
在Activity中调用attach,创建了一个Window
1.创建的window是其子类PhoneWindow,在attach中创建PhoneWindow
2.在Activity中调用setContentView(R.layout.xxx)
3.其中实际上是调用的getWindow().setContentView()
4.调用PhoneWindow中的setContentView方法
5.创建ParentView:作为ViewGroup的子类,实际是创建的DecorView(作为FramLayout的子类)
6.将指定的R.layout.xxx进行填充通过布局填充器进行填充【其中的parent指的就是DecorView】
7.调用到ViewGroup
8.调用ViewGroup的removeAllView(),先将所有的view移除掉
9.添加新的view:addView()

fragment 特点
Fragment可以作为Activity界面的一部分组成出现;
可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用;
在Activity运行过程中,可以添加、移除或者替换Fragment;
Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。

LaunchMode应用场景

standard,创建一个新的Activity。
singleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。
singleTask,回退栈中没有该类型的Activity,创建Activity,否则,onNewIntent+ClearTop。
设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 如果存在这样的Task,它就会在这个Task中启动,否则就会在新的任务栈中启动。因此, 如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。
如果设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。
在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面可以有其他的Activity。这点与singleInstance是有区别的。
singleInstance,回退栈中,只有这一个Activity,没有其他Activity。

singleTop适合接收通知启动的内容显示页面。
例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
singleTask适合作为程序入口点。
例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
singleInstance应用场景:
闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。

Activity,View,Window和WindowManager之间的关系

View:最基本的UI组件,表示屏幕上的一个矩形区域。
Window: 表示一个窗口,包含一个View tree和窗口的layout 参数。View tree的root View可以通过getDecorView得到。还可以设置Window的Content View。
Activity包含一个Window,该Window在Activity的attach方法中通过调用PolicyManager.makeNewWindow创建。
WindowManager:一个interface,继承自ViewManager。 有一个implementation class:android.view.WindowManagerImpl。其实WindowManager并不是整个系统的窗口管理器,而是所在应用进程的窗口管理器。系统全局的窗口管理器运行在SystemServer进程中,是一个Service。ViewRoot通过IWindowSession接口与全局窗口管理器进行交互。 将一个View add到WindowManager时,WindowManagerImpl创建一个ViewRoot来管理该窗口的根View。,并通过ViewRoot.setView方法把该View传给ViewRoot。
ViewRoot用于管理窗口的根View,并和global window manger进行交互。ViewRoot中有一个nested class: W,W是一个Binder子类,用于接收global window manager的各种消息, 如按键消息, 触摸消息等。 ViewRoot有一个W类型的成员mWindow,ViewRoot在Constructor中创建一个W的instance并赋值给mWindow。 ViewRoot是Handler的子类, W会通过Looper把消息传递给ViewRoot。 ViewRoot在setView方法中把mWindow传给sWindowSession。
总之,每个窗口对应着一个Window对象,一个根View和一个ViewRoot对象。要想创建一个窗口,可以调用WindowManager的addView方法,作为参数的view将作为在该窗口上显示的根view。

介绍Activity、Service、Broadcast、BroadcastReceiver、Intent、IntentFilter

Activity
活动(Activity) - 用于表现功能
服务(Service) - 相当于后台运行的 Activity
广播(Broadcast) - 用于发送广播
广播接收器(BroadcastReceiver) - 用于接收广播
Intent - 用于连接以上各个组件,并在其间传递消息
(1)Action也就是要执行的动作
(2)Data,也就是执行动作要操作的数据
(3)type(数据类型)
(4)category(类别)
(5)component(组件)
(6)extras(附加信息)
Intent filters
要告诉android系统哪个intent它们可以处理,activities,services,和 broadcast receivers 必须设置一个或者多个intent过滤器。每个过滤器描述了组件的一种能力,它过滤掉不想要的intent,留下想要的。显示意图则不用考虑这些。
一个过滤器中包含 一个Intent object 中的三个属性 action,data,catrgory 。一个隐式意图必须要通过这三项测试才能传递到 包含该过滤器的组件中

上一篇下一篇

猜你喜欢

热点阅读