安卓Android面试题面试Android 面试专辑

Android面试基础系列一——Android

2017-10-28  本文已影响679人  thinkChao

此系列文章是我在毕业求职期间,对Android面试相关的基础知识做的一个整理,内容还比较全面,现在将其发布出来,希望对即将求职的同学能有帮助。
这一系列的文章都是使用MarkDown编辑的,源文件也一并公布出来,大家可以在我文章的基础上,根据自己的情况修改或增加内容,定制自己的面试笔记。

链接:http://pan.baidu.com/s/1mhM4RSO 密码:hgzt

一、Activity

1、Activity生命周期

可以完整的写下来,注意不要遗漏了onReastart()方法。

2、Android任务栈

而Android是基于组件开发的软件架构,虽然我们开发android程序,仍然使用一个apk工程一个Application的开发形式,但是对于Aplication的开发就用到了Activity、service等四大组件,其中的每一个组件,都是可以被跨应用复用的,这就是android的神奇之处。虽然组件可以跨应用被调用,但是一个组件所在的进程必须是在组件所在的Aplication进程中。由于android强化了组件概念,弱化了Aplication的概念,所以在android程序开发中,A应用的A组件想要使用拍照或录像的功能就可以不用去针对Camera类进行开发,直接调用系统自带的摄像头应用(称其B应用)中的组件(称其B组件)就可以了,但是这就引发了一个新问题,A组件运行在A应用中,B组件运行在B应用中,自然都不在同一个进程中,那么从B组件中返回的时候,如何实现正确返回到A组件呢?Task就是来负责实现这个功能的,它是从用户角度来理解应用而建立的一个抽象概念。因为用户所能看到的组件就是Activity,所以Task可以理解为实现一个功能而负责管理所有用到的Activity实例的栈。

3、Activity启动模式

理解启动模式,还需要看看这篇文章:http://www.jianshu.com/p/2a9fcf3c11e4

4、Activity的启动过程

参考我的博客,面试不会问,可以作为了解。

ActivityThread的main()方法是程序的入口。

5、onSaveInstanceState()与onRestoreInstanceState()

1、onSaveInstanceState()

2、onRestoreInstanceState()

Q1:如果一个Activity在用户可见时才处理某个广播,不可见时注销掉,那么应该在哪两个生命周期的回调方法去注册和注销BroadcastReceiver呢?

A:Activity 的可见生命周期发生在 onStart调用与 onStop调用之间。在这段时间,用户可以在屏幕上看到 Activity 并与其交互。我们可以在 onStart中注册一个 BroadcastReceiver以监控影响 UI 的变化,并在用户无法再看到您显示的内容时在 onStop中将其取消注册。

Q2:如果有一些数据在Activity跳转时(或者离开时)要保存到数据库,那么你认为是在onPause好还是在onStop执行这个操作好呢?

A:这题的要点和上一题是一样的,onPause较容易被触发,所以我们在做BroadcastReceiver注销时放在onStop要好些。onPause时Activity界面仍然是可见的,如弹出一个Dialog时。但在保存数据时,放在onPause去做可以保证数据存储的有效性,如果放在onStop去做,在某些情况下Activity走完onPause后有可能还没顺利走到onStop就被系统回收了。

Q3:简单说一下Activity A启动Activity B时,两个Activity生命周期的变化。

A:
1、Activity A 的 onPause方法执行。

2、Activity B 的 onCreate、onStart和 onResume方法依次执行。

3、然后,如果 Activity A 在屏幕上不再可见,则其 onStop方法执行。

Q4:如何判断Activity是否在运行?
从Activity A 启动一个线程去进行网络上传操作,在A中设立一个回调函数,当上传操作完成以后,在A的这个回调函数中会弹出一个对话框,用来显示回调信息。可是当上传的过程还在进行的时候,我按下back键,A的activity 被销毁了,可是那个上传的线程还在进行,当那个线程结束后,本来应该在A中弹出一个对话框,可是由于A已经不存在了,系统就会报错提示,“将对话框显示在不存在的页面上”,然后程序就挂掉了。

A:我看到过很多人用Handler来充当上面所提到的“回调函数”,即工作线程完成工作后,通过主线程的Handler处理UI更新,如弹出提示Dialog。可能有些人没有弄明白,Activity都被系统销毁了,工作线程怎么还能调它的变量呢?其实所谓的Activity销毁只是不再受系统的AMS控制,但Activity这个对象的实例还是存在于内存中的,具体什么时候真正把这个对象实例也销毁(回收)了,就要看内存回收机制了,哪怕是这个实例没有可达的引用了也不一定会马上回收。

针对这种用Handler更新UI的情况,我们需要在操作UI前判断一下此Activity是否已被销毁。很多人可能都用过isFinishing()来判断,用多了就会发现好象不太准,因为有时候Activity的生命周期没有按我们预想的来走时(如内存紧张时),会出现判断出错的情况。

所以在判断activity是否被回收时,要在添加一个isDestroyed()的判断。

Q5:Activity如何传递参数,并说说Parcelable和Serializable的区别。(day9)

A:使用Intent的Bundle协带参数,就是我们常用的Intent.putExtra方法。

Serializable是Java自带,Parcelable是Android专用。

Serializalbe会使用反射,序列化和反序列化过程需要大量I/O操作。Parcelable自已实现封送和解封,操作不需要用反射,效率要快很多。

6、Activity如何传递数据以及如何进行数据回传

传递数据使用Intent,传输的数据类型包括:基本类型、Bundle、Serializable对象、Parcelable对象。

数据回传使用Activity提供的startActivityForResult(Intent intent,int requestCode)方法。具体使用方式看《Android面试宝典》

7、已调用多个Activity,如何安全退出

1、使用广播,所有开启的Activity都注册有监听此广播的广播接收者,广播接收者收到此类广播后,直接调用finish方法。

2、在Activity的父类当中实现一个集合,在onCreat方法中调用add()方法把启动的Activity加入到集合当中,当退出app时,需要在父类创建一个killAll()方法,在该方法复制一份Activity的集合,遍历集合并销毁Activity。

3、递归退出。使用startActivityForResult()方法打开新的Activity,需要退出时,自定义一个flag标志,在ActivityonActivityResult()方法中处理这个flag,实现递归关闭。

8、如何应对Activity被系统回收

先说说Activity被系统回收的三种情况:

1、内存不足时,后台运行的一些应用程序会被杀死。

2、横竖屏切换时,Activity会被销毁和回收,然后重建

3、长期运行在后台,有时出于省电的目的,会进行回收。

答案就是使用onSavaInstanceState

二、Service

1、功能

Service是一个专门在后台处理长时间任务的Android组件,它没有UI。

Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 UI线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。

如果是Remote Service,那么对应的 Service 则是运行在独立进程的 UI线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!

2、两种启动方式

3、Service与Activity怎么实现通信

1、通过Binder对象。Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法。

2、通过广播。Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好。

4、生命周期

5、Service与Thread

很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面就讲解一下。

Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:一方面,当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。

因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

参考

6、Activity、Intent、Service的关系

一个Activity通常是一个单独的屏幕,每一个Activity都被实现为一个单独的类,这些类都是从Activity基类中继承来的,Activity类显示有视图控件组成的用户接口,并对视图控件的事件做出响应。

Intent的调用是用来进行架构屏幕之间的切换的。Intent是描述应用想要做什么。Intent数据结果中最重要的部分是动作和动作对应的数据,一个动作对应一个动作数据。

Service是运行在后台的代码,不能与用户交互,可以运行在自己的进程,也可以运行在其他应用程序的上下文里。需要通过某一个Activity或其他Context对象来调用。

Activity 跳转到Activity,Activtiy启动Service,Service打开Activity都需要Intent表明跳转的意图,以及传递参数,Intent是这些组件间信号传递者。

7、如何保证 Service 在后台不被 kill

1、提升service优先级

在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。

2、提升service进程优先级

Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:

3、onDestroy方法里重启service

service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;

Q1:Service的onCreate回调函数可以做耗时的操作吗?

A:不可以。Service的onCreate是在主线程(ActivityThread)中调用的,耗时操作会阻塞UI。

8、Service的混合开启模式

start——bind——unbind——stop

这种模式既保证了服务可以长期运行在后台,又可以让调用者远程调用服务中的方法。

三、BroadcastReceiver

1、功能

BroadcastReceiver 是对发送出来的 广播进行过滤、接收和响应的组件。首先将要发送的消息和用于过滤的信息(Action,Category)装入一个 Intent 对象,然后通过调用 Context.sendBroadcast() 、 sendOrderBroadcast() 方法把 Intent 对象以广播形式发送出去。 广播发送出去后,所有已注册的 BroadcastReceiver 会检查注册时的 IntentFilter 是否与发送的 Intent 相匹配,若匹配则会调用 BroadcastReceiver 的 onReceiver() 方法。

2、两种类型

Broadcast被分为两种:

3、两种注册方式

4、内部实现机制

1、自定义广播接收者BroadcastReveiver,并复写onReceive()方法

2、通过Binder机制向AMS进行注册

3、广播发送者通过Binder机制向AMS发送广播

4、AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况是Activity)相应的消息循环队列中

5、消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法

Q1:我们想发送广播只有自己(本进程)能接收到,该如何去做?

A:
1、使用权限,在发送广播时限定有权限(receiverPermission)的接收者才能收到。

2、使用Handler,往主线程的消息池(Message Queue)发送消息,只有主线程的Handler可以分发处理它,广播发送的内容是一个Intent对象,我们可以直接用Message封装一下。在handleMessage时把Intent对象传递给已注册的Receiver。

3、使用LocalBroadcastManager类,其实现方式也是使用Handler,思路和上面也是一样的。

Q2:一个 app 被杀掉进程后,是否还能收到广播?

静态注册的常驻型广播接收器还能接收广播。

四、ContentProvider

这个在面试时一般不怎么问,使用过即可,最好写过相关的demo。

1、ContentProvider、ContentResolver、ContentObserver

五、Intent

Q1: Intent的分类

A1:
1、显式Intent:可以通过类名来找到相应的组件,在应用中用显式Intent去启动一个组件,通常是因为我们知道这个组件(Activity或者Service)的名字。

2、隐式Intent:不指定具体的组件,但是它会声明将要执行的操作,从而匹配到相应的组件。

Intent中包含的属性包括:

Q2: Intent的使用方法,可以传递哪些数据类型?

A2:通过查询Intent/Bundle的API文档,我们可以获知,Intent/Bundle支持传递基本类型的数据和基本类型的数组数据,以及String类型的数据和String类型的数组数据。而对于其它类型的数据貌似无能为力,其实不然,我们可以在Intent/Bundle的API中看到Intent/Bundle还可以传递Parcelable和Serializable类型的数据,以及它们的数组/列表数据。

所以要让非基本类型和非String/CharSequence类型的数据通过Intent/Bundle来进行传输,我们就需要在数据类型中实现Parcelable接口或是Serializable接口。

Q3:介绍一下Intent、IntentFilter

A3:IntentFilter通常是定义在AndroidManifest.xml文件中,也可以动态设置,通常是用来声明组件想要接受哪种Intent。例如,你如果为一个Activity设置了IntentFilter,你就可以在应用内或者其他应用中,用特定的隐式Intent来启动这个Activity,如果没有为Activity设置IntentFilter,那么你就只能通过显示Intent来启动这个Activity。

六、Fragment

1、为什么被称为第五大组件

有人说View是第五大组件,但是View没有生命周期,而Fragment有生命周期,有了周期就可以灵活的进行处理。

但是他并不是完全独立的,虽然有自己的生命周期,但是还是要依附于Activity,同时被加载到Activity当中。

2、Fragment加载到Activity的两种方式

1、静态加载

在XML文件中添加Fragment到Activity的布局文件中。

2、动态加载

使用FragmentManager管理所有要启动的Fragment,
并用FragmentTransaction来添加或替换Fragment,
并用容器资源来作为标志位,设置Fragment将要显示到Activity当中的位置,
最后调用commit方法来完成整个步骤。

3、FragmentPagerAdapter与FragmentStatePagerAdapter的区别

FragmentPagerAdapter适用于页面较少的情况,FragmentStatePagerAdapter则适用于页面较多的情况。

4、Fragment的生命周期

5、Fragment之间的通信

Fragment与Activity

在Fragment中调用Activity中的方法:getActivity()

Fragment与Fragment

在Fragment中调用Fragment中的方法:先调用getActivity(),然后调用findFragmentById()

Activity与Fragment

若activity中包含自己管理的Fragment的引用,则可以直接访问Fragment的公有方法。若没有,则通过getFragmentManager().findFragmentById()获得相应的实例,然后进行操作。

6、Fragment管理器:FragmentManager

7、Fragment的切换

开发的时候,有时候Fragment的切换,是不需要对原先的Fragment进行重新加载的。而Fragment的界面是既可以进行重新加载,也可以不进行重新加载。
每次重新加载的话,我们是使用的replace来进行fragment的替换的。
如果,不对fragment的数据进行重新加载的话,那么就用add来添加fragment,显示的时候用show,切换的时候用hide掉当前的,show切换的目标。

8、Fragment事务

什么是“事务”,一直不明白,不懂。看了《Android面试宝典》,上面说:事务指的就是一种原子性、不可拆分的操作。所谓的Fragment事务,就是对Fragment进行添加、移除、替换或执行其它动作,提交给Activity的每一个变化,这就是Fragment事务。

七、Context

参考文章:Context都没弄明白,还怎么做Android开发?

1、为什么不能 new Activity()

Android程序不能像Java程序一样,随便创建个类,写个Main()方法就能跑了。Android应用模型是基于组件的应用设计模式,组件的运行要有一个完整的Android工程环境,在这个环境下,Activity、Service、BroadcastReceiver等系统组件才能正常工作,而这些组件并不能采用普通的Java对象创建方式,new一下就能创建实例了,而是要有它们各自的上下文环境,也就是Context。

2、Context的继承关系


Context的两个子类分工明确,其中ContextImpl是Context的具体实现类,ContextWrapper是Context的包装类。

Activity、Application、Service虽然都继承自ContextWrapper,但Context的具体实现类是ContextImpl,所以它们的初始化过程都会创建ContextImpl对象有ContextImpl实现Context中的方法。

BroadcastReceiver、ContentProvider并不是Context的子类,它们所持有的Context都是其它地方传过来的,所以不计入Context总数。

一个应用程序中的:Context数量 = Activity数量 + Service数量 + 1(一个Application)

3、生动形象的理解Context

一个Android应用程序,可以理解为一部电影或者一部电视剧,Activity,Service,Broadcast Receiver,Content Provider这四大组件就好比是这部戏里的四个主角。他们是由剧组(系统)一开始就定好了的,整部戏就是由这四位主演领衔担纲的,所以这四位主角并不是大街上随随便便拉个人(new 一个对象)都能演的。有了演员当然也得有摄像机拍摄啊,他们必须通过镜头(Context)才能将戏传递给观众,这也就正对应说四大组件(四位主角)必须工作在Context环境下(摄像机镜头)。那Button,TextView,LinearLayout这些控件呢,就好比是这部戏里的配角或者说群众演员,他们显然没有这么重用,随便一个路人甲路人乙都能演(可以new一个对象),但是他们也必须要面对镜头(工作在Context环境下),所以Button mButton=new Button(Context)是可以的。

4、Context的作用域

从上图我们可以发现Activity所持有的Context的作用域最广,无所不能。因为Activity继承自ContextThemeWrapper,而Application和Service继承自ContextWrapper,很显然ContextThemeWrapper在ContextWrapper的基础上又做了一些操作使得Activity变得更强大。

而且我们可以总结,凡是涉及UI的操作都要在Activity的环境中来执行。

5、Application Context 和 Activity Context 异同

1、Application-Context的生命周期是整个应用,所以,对于它的使用必须慎重,大部分情况下都要避免使用它,因为它会导致内存泄露的问题。

如果我们现在在一个Activity中引入一个Application-Context,那么,当我们这个Activity关闭的时候,这个Application-Context是不会消失的,因为它的生命周期要比我们的Activity长,如果只是一些用来计算的数据还好,但是如果这个Context与我们的Activity的创建有关,或者与我们在Activity要销毁的资源比如图片资源有关,那么,问题就大条了!因为我们的Activity或图片就不能正常销毁,因为它与Application-Context相关联,如果不能正常的释放掉与它们相关的内存,就会出现所谓的内存泄露的问题。这种问题有时候是非常隐晦的,以至于我们根本无法察觉到,所以我们必须遵守相关的使用原则。

2、Activity Context的生命周期是和得到它的引用的Activity一样长,如果这个Activity结束了,那么,这个Context也会得到释放。它并不像我们上面的Application-Context需要特意去获得,可以在一个Activity中使用this就可以获得当前Activity的Context。

八、HandlerThread

Android实现多线程的几种方式

1、介绍

HandlerThread继承于Thread,所以它本质就是个Thread(thread+handler+looper)。与普通Thread的差别就在于,它不仅建立了一个线程,并且创立了消息队列,有自己的looper,可以让我们在自己的线程中分发和处理消息,并对外提供自己这个Looper对象的get方法。

传统的Thread在任务结束后,线程就会被自动销毁,倘若我们又要创建一个新的任务,就不得不重新创建Thread,这样的不断的创建和销毁操作是非常消耗系统资源的。

HandlerThread自带Looper使他可以通过消息队列,来重复使用当前线程,当有耗时任务时,就会执行该任务,没有任务时,循环线程就会处于阻塞状态,等待新的任务,节省系统资源开销。这是它的优点也是缺点,每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

与线程池注重并发不一样,Handler是一个串行队列,因为它背后只有一个线程,当然相对于线程池,它更安全了,因为它不涉及线程间数据的交互问题。

2、使用方法

自己写demo。

九、IntentService

1、概念

IntentService是继承并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service一样。

1、当任务执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf()。

2、另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandlerIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个。所以总结优点:

1、一方面不需要自己去new Thread

2、另一方面不需要考虑在什么时候关闭该Service

2、使用方法

自己写demo。

十、AsyncTask

参考我的博客

十一、AIDL

没用过的话就不会问。
参考我的博客

十二、View

1、绘制流程

参考我的博客

2、事件分发

参考我的博客

3、listView相关

适配器模式

recycleBin机制

recycleBin机制就是调用addScrapView(View scrap,int position)方法,将即将划出屏幕的View进行缓存,这个方法接受的view参数就是刚刚被滑出屏幕的View。这就解释了为什么ListView有几千条数据也不会出现OOM。

优化

与RecyclerView区别

4、自定义View

1、绕不开的几个类

1)Configuration

用来描述设备的配置信息:输入模式、屏幕大小、屏幕方向等。

Configuration config = getResource().getConfiguration();

2)ViewConfiguration

与ViewConfigureation没有什么关系,也不是继承关系。它提供了一些自定义控件用到的标准常量,比如UI超时(按住状态转变为长按状态需要的时间)、尺寸大小、滑动距离、敏感度等等。

ViewConfiguration viewConfig = ViewConfiguration.get(context);
//获取touchSlop(滑动最少多少才算滑动)
int touchSlop = viewConfig.getScaledTouchSlop();

3)GestureDetector

主要作用是简化Touch操作。

4)VelocityTracker

用于跟踪触摸屏事件的速度。使用步骤:

1)开始追踪

mVelocityTracker.addMovment(event);

2)获取速度

mVelocityTracker.gerXVelocity(); //获取X方向的速度
mVelocityTracker.gerYVelocity(); //获取Y方向的速度

3)停止追踪

mVelocityTracker.recycle();
mVelocityTracker = null;

5)Scroller

scroll的本质:滑动的本质是滑动view的内容。

6)ViewDragHelper

用于简化View的拖拽的相关操作。

2、常见实现方式

1)继承自View

这里要注意处理Measure过程中,对”wrap_content“属性的处理。具体什么问题可以看我之前写的一篇文章,如果不想这么麻烦,就用第二种方法,除非不得已。

2)继承自系统已有的View

3)继承自ViewGroup

这里要亲自处理Layout方法,因为不同的ViewGroup(比如线性布局、相对布局),布局方式是不一样的。同样如果不想麻烦,就用第四种方法,除非不得已。

4)继承自系统已有的ViewGroup

5、屏幕适配

**px: **pixel,即像素,1px代表屏幕上的一个物理的像素点。但px单位不被建议使用。因为同样像素大小的图片在不同手机显示的实际大小可能不同。要用到px的情况是需要画1像素表格线或阴影线的时候,如果用其他单位画则会显得模糊。

**dip (dp): **device independent pixel。dp (dip)是最常用也是最难理解的尺寸单位。与像素密度密切相关。Android系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi),它们对应的dp到px的系数分别为0.75、1、1.5和2,这个系数乘以dp长度就是像素数。例如界面上有一个长度为“80dp”的图片,那么它在240dpi的手机上实际显示为80x1.5=120px,在320dpi的手机上实际显示为80x2=160px。如果你拿这两部手机放在一起对比,会发现这个图片的物理尺寸“差不多”,这就是使用dp作为单位的效果。

**sp: **Scale-independent Pixel,即与缩放无关的抽象像素。sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时,1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。

6、动画

Android 起初有两种动画:Frame Animation(逐帧动画) Tween Animation(补间动画),但是在用的时候发现这两种动画有时候并不能满足我们的一些需要,所以Google在Androi3.0的时候推出了(Property Animation)属性动画,至于为什么前边的两种动画不能满足我们的需要,请往下看:

1、Frame Animation(逐帧动画)

逐帧动画就是UI设计多张图片组成一个动画,然后将它们组合链接起来进行动画播放。该方式类似于早期电影的制作原理:具体实现方式就不多说了,你只需要让你们的UI出多张图片,然后你顺序的组合就可以(前提是UI给您做图)

2、Tween Animation(补间动画)

Tween Animation:是对某个View进行一系列的动画的操作,包括淡入淡出(Alpha),缩放(Scale),平移(Translate),旋转(Rotate)四种模式

Tween Animation(补间动画)的一些缺点:

Tween Animation(补间动画)只是针对于View,超脱了View就无法操作了,这句话的意思是:假如我们需要对一个Button,ImageView,LinearLayout或者是其他的继承自View的各种组件进行动画的操作时,Tween Animation是可以帮我们完成我们需要完成的功能的,但是如果我们需要用到对一个非View的对象进行动画操作的话,那么补间动画就没办法实现了。举个例子:比如我们有一个自定义的View,在这个View中有一个Point对象用于管理坐标,然后在onDraw()方法中的坐标就是根据该Pointde坐标值进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义的View,那么整个自继承View的当前类就都有了动画,但是我们的目的是不想让View有动画,只是对动画中的Point坐标产生动画,这样补间动画就不能满足了。

Tween Animation动画有四种动画操作(移动,缩放,旋转,淡入淡出),但是我们现在有个需求就是将当前View的背景色进行改变呢?抱歉Tween Animation是不能帮助我们实现的。

Tween Animation动画只是改变View的显示效果而已,但是不会真正的去改变View的属性,举个例子:我们现在屏幕的顶部有一个小球,然后通过补间动画让他移动到右下角,然后我们给这个小球添加了点击事件,希望位置移动到右下角的时候点击小球能的放大小球。但是点击事件是绝对不会触发的,原因是补间动画只是将该小球绘制到了屏幕的右下角,实际这个小球还是停在屏幕的顶部,所以你在右下角点击是没有任何反应的。
Property Animatior(属性动画)

3、属性动画是Android3.0之后引进的,它更改的是动画的实际属性,在Tween Animation(补间动画)中,其改变的是View的绘制效果,真正的View的属性是改变不了的,比如你将你的Button位置移动之后你再次点击Button是没有任何点击效果的,或者是你如何缩放你的Button大小,缩放后的有效的点击区域还是只有你当初初始的Button的大小的点击区域,其位置和大小的属性并没有改变。而在Property Animator(属性动画)中,改变的是动画的实际属性,如Button的缩放,Button的位置和大小属性值都会发生改变。而且Property Animation不止可以应用于View,还可以应用于任何对象,Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。

十三、数据存储

sqlite

自己写demo。

主要类为:SqliteOpenHelper、SqliteDatabase、Cursor

SharedPreference

除SQLite数据库外,另一种常用的数据存储方式,其本质就是一个xml文件,常用于存储较简单的参数设置。

File

即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的事情。

数据量非常少,可以使用文件。
如果涉及到查询等操作,并且数据量大,则应该使用数据库。

十四、Android项目构建

1、构建流程

2、Git

工作流

3、Gradle

4、Proguard

十三、框架层源码

都参考我的博客。

1、AMS、WMS

https://thinkchao.github.io/2017/07/17/android-10/

2、Handler

https://thinkchao.github.io/2017/06/25/android-1/

3、AsyncTask

https://thinkchao.github.io/2017/07/23/android-12/

十五、第三方框架

1、OkHttp

了解和使用

了解

使用

1、创建OkHttpClient对象

OkHttpClient okHttp = new OkHttpClient();

全局对象,所有的Http请求都共用这一个,和Volley的第一步一样。
2、创建request对象

Request request = new Request.Builder().url(……).build();

3、创建一个Call对象
调用newcall(request)).execute();,同步获取数据,阻塞当前进程。

或调用newcall(request).enqueue();,异步获取数据,开启一个子线程。请求成功回调OnReponse()方法,请求失败回调OnFailure()方法。

2、Volley

http://extremej.itscoder.com/volley_source/#

了解和使用

了解

使用

http://blog.csdn.net/guolin_blog/article/details/17482095
1、创建 RequestQueue

RequestQueue mRequestQueue = Volley.newRequestQueue(this);

2、接下来为了要发出一条HTTP请求,我们还需要创建一个StringRequest对象

StringRequest stringRequest = new StringRequest(………………);

StringRequest的构造函数需要传入三个参数:
第一个参数就是目标服务器的URL地址;
第二个参数是服务器响应成功的回调;
第三个参数是服务器响应失败的回调。
3、最后,将这个StringRequest对象添加到RequestQueue里面就可以了

mQueue.add(stringRequest);  

代码逻辑

3、Retrofit

http://www.jianshu.com/p/45cb536be2f4

4、Glide

5、RxJava

http://gank.io/post/560e15be2dca930e00da1083

了解与使用

了解

RxJava 的本质可以压缩为异步这一个词。说到根上,它就是一个实现异步操作的库,而别的定语都是基于这之上的。

同样是做异步,为什么人们用它,而不用现成的 AsyncTask / Handler / XXX / ...?

异步操作很关键的一点是程序的简洁性,因为在调度过程比较复杂的情况下,异步代码经常会既难写也难被读懂。 Android 创造的 AsyncTask 和Handler ,其实都是为了让异步代码更加简洁。RxJava 的优势也是简洁,但它的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁。

十六、Android热门前沿知识

1、MVC

采用MVC的好处就是便于UI界面的显示和业务逻辑的分离,具体来说:Model层主要用于业务逻辑的处理,比如数据库、网络操作;View层主要用于视图的显示,也就是xml里的内容;Ctroller层用于处理用户和界面的交互,通过读取VIew层的数据,然后将数据交给界面来显示。

优点:

1、耦合性低

2、可扩展性好

3、模块职责划分明确

缺点:

View层对应的是Android中的xml布局文件,而布局文件并不像java web那么强大,能做的处理很有限,所以很多View层该做的操作就交给了Activity,它里面负责了很多操作UI的业务逻辑,而这些功能明显是应该交给View层来做的,这就导致了Activity的冗余。

2、MVP

优点:

耦合性更低,与MVC最大的区别就是Model层和View层不再有交互,而是通过Presenter层交互。如图:

需要注意的一点是,Presenter层的实现必须通过接口定义,这个需要在实战中去了解。

3、MVVM

理论上比MVP更先进,但实战用的很少。

4、插件化

插件化来由

65536/64K ,当方法达到65536个的时候,就不能再创建新的方法。

所谓插件化,就是让我们的应用不必再像原来一样把所有的内容都放在一个apk中,可以把一些功能和逻辑单独抽出来放在插件apk中,然后主apk做到按需调用,这样的好处是一来可以减少主apk的体积,让应用更轻便,二来可以做到热插拔,更加动态化。

要解决的问题

1、动态加载apk

2、代码加载

3、资源加载

5、热更新

6、进程保活

概念

想要我们的进程在内存中永远存在,杀不死,就算杀死了,也能让它马上重启。

进程的优先级

1、前台进程:前台进程是目前正在屏幕上显示的进程和一些系统进程,也就是和用户正在交互的进程。例如,我正在使用qq跟别人聊天,在我的android手机上这个进程就应该是前台进程。

2、可见进程:可见进程指部分程序界面能够被用户看见,却不在前台与用户交互的进程。例如,我们在一个界面上弹出一个对话框(该对话框是一个新的Activity),那么在对话框后面的原界面是可见的,但是并没有与用户进行交互,那么原界面就是可见进程。

3、服务进程:服务进程是通过 startService() 方法启动的进程,但不属于前台进程和可见进程。例如,在后台播放音乐或者在后台下载就是服务进程。

4、后台进程:后台进程指的是目前对用户不可见的进程。例如我正在使用qq和别人聊天,这个时候qq是前台进程,但是当我点击Home键让qq界面消失的时候,这个时候它就转换成了后台进程。当内存不够的时候,可能会将后台进程回收。

5、空进程:空进程指的是在这些进程内部,没有任何东西在运行。保留这种进程的的唯一目的是用作缓存,以缩短该应用下次在其中运行组件所需的启动时间。

前三个进程,内存够用的情况下,是不会回收的,而后两个系统可以随意的进行回收。

进程回收策略

进程保活方案

1、利用系统广播拉活

2、利用系统Service机制拉活

3、利用Native进程拉活

7、Kotlin

概念

8、ReactNative、WebView

目前主流的APP开发方式主要以下四种:

Native App

就是所说的原生开发,Native Code编程,代码编译之后以2进制或者字节码的形式运行在OS上,直接调用OS的API。

Web App

以HTML+JS+CSS等WEB技术编程,代码运行在浏览器中,通过浏览器来调用API(取决于HTML5未来的支持能力)。

Hybrid App

就是混合开发。部分代码以WEB技术编程,部分代码由某些Native Container承担(例如PhonGAP插件,BAE插件),其目的是在HTML5尚未完全支持Device API和Network API的目前阶段,承担这部分职责。常用的技术就是webview+html5。

Hybrid模式下,由原生提供统一的API给JS调用,实际的主要逻辑有Html和JS来完成,而由于最终是放在webview中显示的,所以只需要写一套代码即可,达到跨平台效果,另外也可以直接在浏览器中调试,

ReactNative

Facebook发起的开源的一套新的APP开发方案,使用JS+部分原生语法来实现功能。不同于H5,也不同于原生,更像是用JS写出原生应用。

对比

9、Android8.0

十七、Dalvik虚拟机及系统服务

Dalvik架构

Binder机制

Zygote、SystemServer

十八、优化

1、绘制优化

就是针对meaure、layout、draw三个过程中可能遇到的问题进行优化。

工具

布局优化

OverDraw

Layout太复杂。

频繁重新渲染

UI卡顿原因

2、内存优化

工具

3、安装包大小优化

4、耗电优化

5、异常

1)ANR(application not responding)

产生原因

这个异常经常会遇到,它会弹出一个对话框,让用户选择是等待还是关闭程序。

在Activity最长的执行时间是5s,Service中是20s,BroadcastReceiver中,最长的执行时间是10s,如果在这个事件内没有完成,系统就会弹出这个对话框,主要是由WMS和AMS监视的。所以可见,产生这个异常的原因就是在主线程中做了耗时操作。

解决

1、使用AsyncTask处理耗时IO操作

2、使用handler处理工作线程的耗时任务

3、Activity的onCreate()和onResume()回调中尽量避免耗时的代码

2)OOM(out of memory)

产生原因

当前占用的内存加上我们申请的内存超过了Dalvik虚拟机最大的内存限制就会抛出该异常。

关于内存异常容易混淆的概念

3)内存泄漏

《Android面试宝典》P115

十九、其它问题

1、自我介绍

2、我的优缺点

优点

缺点

3、还有什么问题想要问吗

技术面

1、刚才在面试的时候,如果有没回答上来的,就可以问面试官。

2、您觉得我还要加强哪方面的能力?

诸如此类的问题吧

hr面

4、公司了解

规模

产品

为什么想来我们公司

5、项目或论文相关

这个还是挺重要的,根据个人情况,要好好准备,一定要把一些细节要琢磨透。

6、在校期间都做过什么?

如果你是研究生,面试官就会询问你的研究领域,这个也要准备准备,一定要表达清晰。

7、平时写什么代码写的比较多,除了看框架代码,自己有去写过什么吗?

8、为什么没有去实习?

如果你没出去实习过,有可能会被问到这个问题。

上一篇下一篇

猜你喜欢

热点阅读