您的位置:首页 > 职场人生

面试准备android(四)

2016-04-17 16:11 337 查看
这一篇主要是android的基础知识了解,还有一些server的处理使用等,慢慢发,因为最近腾讯面试导致心情不好。。。好吧,是相当不好……(╥﹏╥)

------------我是悲伤的分割线-----------------

(5.4五一小长假完了,继续准备携程boss面,把之前缺的补上来,有些事情靠运气,但是别忘了运气来时你得有实力!)

-----------我是焦急的分割线----------------

1.Activity与Fragment(碎片)的生命周期。(左:生命周期图右:Fragment与Activity生命周期对比图)



resumed(重新开始),detach(拆卸)

2.Acitivty的四中启动模式与特点。

如果要使用这四种启动模式,必须在manifest文件中标签中的launchMode属性中配置

standard:activity的默认启动模式。在这种模式下启动的activity可以被多次实例化,即在同一个任务中可以存在多个activity的实例,每个实例都会处理一个Intent对象。如果Activity A的启动模式为standard,并且A已经启动,在A中再次启动Activity A,即调用startActivity(new Intent(this,A.class)),会在A的上面再次启动一个A的实例,即当前的桟中的状态为A–>A。

singleTop:举例来说,如果A的启动模式为singleTop,且A的一个实例已经存在于栈顶中,再调用startActivity(new Intent(this,A.class))启动A时,不会再次创建A的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()方法。这是任务桟中还是这有一个A的实例。如果不在桟顶,那么它的行为和standard模式相同,也会创建多个实例。

singleTask:启动模式为singleTask,那么系统总会在一个新任务的最底部(root)启动这个activity,并且被这个activity启动的其他activity会和该activity同时存在于这个新任务中。如果系统中已经存在这样的一个activity则会重用这个实例,并且调用他的onNewIntent()方法。即,这样的一个activity在系统中只会存在一个实例。

singleInstance:总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。

3.Activity缓存方法。

onSaveInstanceState()回调方法保存临时数据和状态,这个方法一定会在活动被回收之前调用。onRestoreInstanceState(http://m.blog.csdn.net/article/details?id=49833891

4.Service的生命周期,两种启动方法,有什么区别。

如果在Service的onCreate或者onStart做一些很耗时间的事情,最好在 Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到UI操作或者阻塞主线程中的其他事情。 (只有onStart可被多次调用)

Context.startService() :Service会经历 onCreate -> onStart, stopService的时候直接onDestroy ,如果是调用者(TestServiceHolder)自己直接退出而没有调用stopService的话,Service会一直在后台运行。 下次TestServiceHolder再起来可以stopService。

什么时候需要Service :

比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等, 后台运行,可交互这样的一个东西。它跟Activity的级别差不多,但是他 不能自己运行,需要通过某一个Activity或者其他Context对象来调用。

5.怎么保证service不被杀死。

/article/7659446.html

Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过来声明。可以通过contect.startservice和contect.bindserverice来启动。和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现(或者用系统提供的IntentService,它继承了Service,它处理数据是用自身新开的线程)。【当然也可以在新的线程中startService,这样Service就不是在MainThread了】

方法1:(提高优先级)用户不干预,完全靠系统来控制。比如 onStartCommand() 方法的返回值设为 START_STICKY ,服务就会在资源紧张的时候被杀掉,然后在资源足够的时候再恢复。当然也可设置为前台服务,使其有高的优先级,在资源紧张的时候也不会被杀掉。借助第三方应用kill掉running task,使用startForeground(true) 将service放到前台状态。这样在低内存时被kill的几率会低一些;在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级

方法2:(监听ondestory)用户干预,主动杀掉运行中的服务。这个过程杀死服务会通过服务的生命周期,也就是会调用 onDestory() 方法,这时候一个方案就是在 onDestory() 中发送广播开启自己。这样杀死服务后会立即启动。当service走settings 的ondestory的时候,发送一个自定义的广播,当收到广播的时候,startService进行Service的重启;settings中force stop 应用捕捉系统进行广播(action为android.intent.action.PACKAGE_RESTARTED)

方法3:(循环监听)jni中循环监听服务的状态,如果被停止了。但有些情况下,发送的广播在消息队列中排的靠后,就有可能服务还没接收到广播就销毁了(所以为了能让这个机制完美运行,可以开启两个服务,相互监听,相互启动。服务A监听B的广播来启动B,服务B监听A的广播来启动A。

6.广播的两种注册方法,有什么区别。

常驻型广播:当你的应用程序关闭了,如果有广播信息来,你写的广播接收器同样的能接受到,他的注册方式就是在你的应用程序中的AndroidManifast.xml进行注册。通常说这种方式是静态注册

非常驻型广播:当应用程序结束了,广播自然就没有了,比如你在activity中的onCreate或者onResume中注册广播接收器,在onDestory中卸载广播接收器。这样你的广播接收器就一个非常驻型的了。这种也叫动态注册。

7. Intent的使用方法,可以传递哪些数据类型。

intent应用场合:启动一个Activity;启动一个Service;启动一个Broadcast;

具体:http://bbs.9ria.com/thread-210777-1-1.html

可以传递数据类型: A、Serializable B、charsequence C、Parcelable D、Bundle

/article/5829033.html

Serializable(可串行的)是java提供的通用数据保存和读取的接口。序列化类的所有子类本身都是可序列化的。这个序列化接口没有任何方法和域,仅用于标识序列化的语意。允许非序列化类的子类型序列化。Parcelable(可打包的)也是实现序列化,比前者更高效更复杂。

charsequence接口,实现了这个接口的类有:CharBuffer、String、StringBuffer、StringBuilder这个四个类。

Bundle是将数据传递到另一个上下文中或保存或回复你自己状态的数据存储方式。它的数据不是持久化状态。)

/article/2518806.html

8. ContentProvider使用方法。

Content Provider为存储数据和获取数据提供了统一的接口,它可以完成在不同应用程序下的数据共享,SQLite只能在同一个程序中共享数据。。它能够实现跨应用之间的数据操作。利用ContentResolver对象的delete、update、insert、query等方法去操ContentProvider的对象,让ContentProvider对象的方法去对数据操作。

实现方式为:

1、ContentProvider使用表的形式来组织数据:无论数据的来源是什么,ContentProvider都会认为是一种表,然后把数据组织成表格

2、ContentProvider提供的方法:query:查询 insert:插入;update:更新; delete:删除; getType:得到数据类型 onCreate:创建数据时调用的回调函数

3、每个ContentProvider都有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。Android所提供的ContentProvider都存放在android.provider包当中

9. Thread、AsycTask、IntentService的使用场景与特点。

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

(其他的:线程的上下文切换实际上就是 存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。

  虽然多线程可以使得任务执行的效率得到提升,但是由于在线程切换时同样会带来一定的开销代价,并且多个线程会导致系统资源占用的增加,所以在进行多线程编程时要注意这些因素。

location serivce 不是一个单独的进程,它和应用程序在同一个进程中。只能在当前应用中调用service。kill当前应用则service也随之消亡。

remote service 独立与应用程序之外进程的进程(必须在声明的时候以android:process=”:remote”方式声明),配合AIDL可以实现进程间的相互调用。remote service所依附的那个应用如果应用kill掉,但是remoteservice还在运行,除非你卸载当前应用。 )

IntentService 是Serivce+handler的结合产物,可以在onHandleIntent直接处理耗时操作。而本地service和远程service不能在onStart方法中执行耗时操作,只能放在子线程中进行处理,当有新的intent请求过来都会先onStartCommond将其入队列,当第一个耗时操作结束后,就会处理下一个耗时操作(此时调用onHandleIntent),都执行完了自动执行onDestory销毁IntengService服务。

AsyncTask是thread池+handler的结合产物,减少程序中线程过多开销过大,操作和管理更加方便。AsyncTask实例必须在UI Thread中创建,execute方法必须在UI Thread中调用不能手动调用onPreExcute(),onPostExcute(Result)。task只能被执行一次,否则将出现异常。

数据简单使用AsyncTask:实现代码简单, 数据量多且复杂使用handler+thread :相比较AsyncTask来说能更好的利用系统资源且高效

10. 五种布局: FrameLayout 、 LinearLayout 、 AbsoluteLayout 、 RelativeLayout 、 TableLayout 各自特点及绘制效率对比。

(特征:http://www.xuebuyuan.com/1975042.html

11. Android的数据存储形式。

/article/4962248.html

SharePreference :轻型的数据存储方式,实际上是基于XML文件存储的“key-value”键值对数据。通常用来存储程序的一些配置信息。其存储在“data/data/程序包名/shared_prefs目录下。

SharedPreference本身只能获取数据,不支持存储和修改。存储和修改要通过Editor对象来实现。

SQLite 是一个轻量级关系型数据库 特点:面向资源有限的设备 ,没有服务器进程,所有数据存放在同一文件中跨平台,可自由复制。

File 文件可用来存放大量数据,如文本、图片、音频等。可以存放在sd卡

默认位置:/data/data/< >/files/.

ContentProvider看第8点

Android系统中数据基本都是私有的,一般存放在“data/data/程序包名”目录下。如果要实现数据共享,正确的方式是使用ContentProvider。

12.Sqlite的基本操作。

~创建和打开一个数据库都可以使用openOrCreateDatabase 方法来实现,创建成功则返回一个 SQLiteDatabase对象,否则抛出异常FileNotFoundException。

~INSERT INTO table1 (_id, num, data) values (1, 1, ‘通过SQL语句插入’)” ;

~”DELETE FROM table1 WHERE _id=1”;

.close();

DROP TABLE table1”

mSQLiteDatabase.execSQL(INSERT_DATA);

13.Android中的MVC模式。

是模型(model)-视图(view)-控制器(controller)用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

M层:数据处理,业务逻辑处理,比如数据库存取操作,网络操作,复杂的算法,耗时的任务等都在model层处理。

V层:数据显示的处理,XML布局可以视为V层,显示Model层的数据结果。

C层:桥梁的作用,来控制V层和M层通信以此来达到分离视图显示和业务逻辑层。在Android中,Activity处理用户交互问题,因此可以认为Activity是控制器,Activity读取V视图层的数据(eg.读取当前EditText控件的数据),控制用户输入(eg.EditText控件数据的输入),并向Model发送数据请求(eg.发起网络请求等)。

android项目中:业务逻辑,数据处理等担任了Model(模型)角色,XML界面显示等担任了View(视图)角色,Activity担任了Contronller(控制器)角色

MVC的优点:

(1)耦合性低。所谓耦合性就是模块代码之间的关联程度。利用MVC框架使得View(视图)层和Model(模型)层可以很好的分离,这样就达到了解耦的目的,所以耦合性低,减少模块代码之间的相互影响。

(2)可扩展性好。由于耦合性低,添加需求,扩展代码就可以减少修改之前的代码,降低bug的出现率。

(3)模块职责划分明确。主要划分层M,V,C三个模块,利于代码的维护。

14.Include、Merge、ViewStub的作用。

:布局重用,标签能够重用布局文件,在include标签中所有的android:layout_*都是有效的,前提是必须要写layout_width和layout_height两个属性。

:减少视图层级,多用于替换FrameLayout或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用标签优化。

:最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。是一个不可见的,大小为0的View。

15.Json有什么优劣势。(Json和XML优缺点比较http://blog.sina.com.cn/s/blog_8a30865f0101amjh.html

在解码难度方面,XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。

JSON和XML同样拥有丰富的解析手段。数据的体积小。与JavaScript的交互更加方便。速度要远远快于XML。

JSON对数据的描述性比XML较差。

16.动画有哪两类,各有什么特点?

一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转、平移、放缩和渐变) /article/1892133.html

alpha 渐变透明度

scale 渐变大小尺寸伸缩动画

translate 画面位置移动

rotate 画面旋转动画

二类就是Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似

17.Handler、Loop消息队列模型,各部分的作用。

Handler是一个消息系统的外壳,属于某个Thread并包装了Thread的Looper及其MessageQueue;与外部进行交互(同一个线程内或者线程之间),接收派发和处理消息,消息系统模型的核心是Looper。

Handler能够让你发送和处理消息,以及Runnable对象;每个Handler对象对应一个Thread和Thread的消息队列。当你创建一个Handler时,它就和Thread的消息队列绑定在一起,然后就可以传递消息和runnable对象到消息队列中,执行消息后就从消息队列中退出。


handler干了些什么:——建立消息处理模型/系统。

 运行在某个线程上,共享线程的消息队列;

  接收、调度,派发和处理消息;

  实现消息的异步处理;

某个Thread并包装了Thread的Looper及MessageQueue;与外部进行交互(同一个线程内或者线程之间),接收派发和处理消息,

Looper:实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的既没有Looper;需要主动去创建,然后启动Looper的消息循环loop;与外部的交互通过Handler进行;消息循环和消息队列都是由Looper建立的,而建立Handler的关键就是这个Looper。

18.怎样退出终止App。(ps:finish()结束当前的activity)

public void exit(){

for (Activity activity : activities) {

if (activity!=null) {

activity.finish();} }

System.exit(0);}

19.Asset目录与res目录的区别。

assets:用于存放需要打包到应用程序的静态文件,以便部署到设备中。支持任意深度的子目录。这些文件不会生成任何资源ID,必须使用/assets开始(不包含它)的相对路径名。

res:用于存放应用程序的资源(如图标、GUI布局等),将被打包到编译后的Java中。不支持深度子目录

20.Android怎么加速启动Activity。

(优化:因为初始化解析界面时需要一定时间,解决方法是自定义Theme(设置一张待显示的图片)。 http://www.aliog.com/733.html )

21.Android内存优化方法:ListView优化,及时关闭资源,图片缓存等等。

http://androidperformance.com/2015/07/20/Android-Performance-Memory-AndroidResource.html内存优化总 )

(listview优化http://www.bkjia.com/Androidjc/1027414.html

Bitmap优化

1.1 主动释放Bitmap资源

当确定这个Bitmap资源不会再被使用的时候手动调用recycle()方法,释放其Native内存

调用bitmap.recycle之后,这个Bitmap如果没有被引用到,那么就会被垃圾回收器回收。如果不主动调用这个方法,垃圾回收器也会进行回收工作,只不过垃圾回收器的不确定性太大,依赖其自动回收不靠谱(比如垃圾回收器一次性要回收好多Bitmap,那么需要的时间就会很多,导致回收的时候会卡顿)。所以我们需要主动调用recycle。

1.2 主动释放ImageView的图片资源和背景资源

1.4 尽量少用Png图,多用NinePatch(拉伸后不变形图)的图

1.5 使用大图之前,尽量先对其进行压缩

2 查询数据库未关闭游标Cursor

如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。

3 构造Adapter时,没有使用缓存的convertView

以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法:

public View getView(int position, View convertView, ViewGroup parent)

来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参 View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。

4 释放对象的引用

一个对象的内存没有被释放是因为他被其他的对象所引用,系统不回去释放这些有GC Root的对象。

5 在Activity的生命周期中释放资源

Android应用程序中最典型的需要注意释放资源的情况是在Activity的生命周期中,在onPause()、onStop()、onDestroy()方法中需要适当的释放资源的情况。

6 消除过渡绘制

过渡绘制指的是在屏幕一个像素上绘制多次(超过一次),比如一个TextView后有背景,那么显示文本的像素至少绘了两次,一次是背景,一次是文本。GPU过度绘制或多或少对性能有些影响,设备的内存带宽是有限的,当过度绘制导致应用需要更多的带宽(超过了可用带宽)的时候性能就会降低。带宽的限制每个设备都可能是不一样的。

过渡绘制的原因:同一层级的View叠加,复杂的层级叠加

23.Bitmap的四种属性,与每种属性队形的大小。(找不到。。)

24.View与View Group分类。

ViewGroup的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。View的相关事件只有两个:dispatchTouchEvent、onTouchEvent。

View类是它称为“widgets(工具)”的子类的基础,它们提供了诸如文本输入框和按钮之类的UI对象的完整实现。

  ViewGroup类同样为其被称为“Layouts(布局)”的子类奠定了基础,它们提供了象流式布局、表格布局以及相对布局之类的布局架构。

View的介绍

(1) 事件和绘制

绘制流程:绘制按照视图树的顺序执行。视图绘制时会先绘制子控件。如果视图的背景可见,视图会在调用onDraw函数之前绘制背景。强制重绘,可以使用invalidate()。

事件的基本流程如下:

1、事件分配给相应视图,视图处理它,并通知相关监听器。

2、操作过程中如果发生视图的尺寸变化,则该视图用调用requestLayout()方法,向父控件请求再次布局。

3、操作过程中如果发生视图的外观变化,则该视图用调用invalidate()方法,请求重绘。

4、如果requestLayout()或invalidate()有一个被调用,框架会对视图树进行相关的测量、布局和绘制。

注意,视图树是单线程操作,直接调用其它视图的方法必须要在UI线程里。跨线程的操作必须使用句柄Handler。

焦点处理:

框架处理焦点的转移,来响应用户输入。isFocusable()函数表示视图是否能接受焦点。setFocusable(boolean)函数可以改变视图能否接受焦点。触摸屏模式(Touch Mode)的相关函数是isFocusableInTouchMode()和setFocusableInTouchMode(boolean)。

焦点转移按照就近算法。按哪个方向就近可以在XML布局文件中配置。

视图请求焦点可以使用requestFocus()。

自定义View过程:onMeasure()、onLayout()、onDraw()。

(重载onMeasure()[本身大小],onLayout()[位置],onDraw()[如何绘制]三个函数构建了自定义View的外观形象)

25.Touch事件分发机制。



26.Android长连接,怎么处理心跳机制。

 虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能,但是明显来说Push方式比Pull方式更优越。因为Pull方式更费客户端的网络流量,更主要的是费电量,还需要我们的程序不停地去监测服务端的变化。 

MTQQ机制:/article/8174549.html

27.Zygote的启动过程。(偏低层,不用深入了解)

而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。

28.Android IPC:Binder原理。(http://blog.sina.com.cn/s/blog_40e9d4dd0100xiee.html

出于保护机制,一个进程不能直接访问另一个进程的资源,进程之间互相封闭。但是,在一个复杂的应用系统中,通常会使用多个相关的进程来共同完成一项任务,因此要求进程之间必须能够互相通信,从而共享资源和信息。所以,操作系统内核必须提供进程间的通信机制(IPC)。在Linux中,进程间的通信机制有很多种,例如可以采用命名管道(named pipe)、消息队列(message queue)、信号(signal)、共享内存(share memory)、socket等方式,它们都可以实现进程间的通信。但是,在Android终端上的应用软件的通信几乎看不到这些IPC通信方式,取而代之的是Binder方式。

优点:因为Binder更加简洁和快速,消耗的内存资源更小,传统的进程间通信可能会增加进程的开销,而且有进程过载和安全漏洞等方面的风险

原理:

两个进程间通信看起来就像是一个进程进入另一个进程去执行代码,然后带着执行的结果返回。Binder的用户空间为每一个进程维护着一个可用的线程池,线程池用于处理到来的IPC以及执行进程的本地消息,Binder通信是同步。同时,Binder机制是基于OpenBinder,主要通过binder_ioctl函数与用户空间的进程交换数据。Client和Server均通过函数ioctl与Binder驱动进行数据交互。ioctl是Linux中用于控制I/O设备的函数,提供了一种同时向设备发送控制参数和数据的手段。它是一个可变参数的函数,

Binder通信也是基于Service与Client的,所有需要IBinder通信的进程都必须创建一个IBinder接口。系统中有一个名为Service Manager的守护进程管理着系统中的各个服务,它负责监听是否有其他程序向其发送请求,如果有请求就响应,如果没有则继续监听等待。每个服务都要在Service Manager中注册,而请求服务的客户端则向Service Manager请求服务。在Android虚拟机启动之前,系统会先启动Service Manager进程,Service Manager就会打开Binder驱动,并通知Binder Kernel驱动程序,这个进程将作为System Service Manager,然后该进程将进入一个循环,等待处理来自其他进程的数据。因此,我们也可以将Binder的实现大致分为:Binder驱动、Service Manager、Service、Client这几个部分,下面将分别对这几个部分进行详细分析。

29.你用过什么框架,是否看过源码,是否知道底层原理。

30.Android5.0、6.0新特性。

Android的话,多是一些项目中的实践,使用多了,自然就知道了,还有就是多逛逛一些名人的博客,书上能讲到的东西不多。另外android底层的东西,有时间的话可以多了解一下,加分项。

-----------------------------------

推荐书籍:《疯狂android讲义》《深入理解android》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: