[Android面试题]--2015-2016高发面试题基础版(你一定会遇到)

╰+攻爆jí腚メ 2022-09-21 05:48 106阅读 0赞

本文集锦自面试过程中常遇到的问题,都是大家实际遇到的,都是平常收集的,如果你正在求职看一看肯定会帮助很大,如果在工作中也可以读一读巩固基础以查漏补缺. 辛苦整理希望只对大家有帮助!




























































某公司高级面试题(2015-03-14)【感谢helder分享】


1、详述Android系统架构,包括层与层之间调用、binder、jni、底层文件读写方法

2、描述自己的一个项目,要求画出结构图,UML图,详细描述项目种的技术点,技术难点以及解决方案


3、一道算法


4、谈谈自己项目管理的方法、对敏捷软件开发的理解




基础面试题(2014-04-18)


1、请解释下在单线程模型中Message,Handler,Message Queue,Looper之间的关系。


拿主线程来说,主线程启动时会调用Looper.prepare()方法,会初始化一个Looper,放入Threadlocal中,接着调用Looper.loop()不断遍历Message Queue,


Handler的创建依赖与当前线程中的Looper,如果当前线程没有Looper则必须调用Looper.prepare()。Handler , sendMessage到MessageQueue,Looper不断


从MessageQueue中取出消息,回调handleMessage方法。




2、如果有个100M大的文件,需要上传至服务器中,而服务器form表单最大只能上传2M,可以用什么方法。


这个问题不是很明确我觉得,首先来说使用http协议上传数据,特别在android下,跟form没什么关系。传统的在web中,在form中写文件上传,其实浏览器所做


的就是将我们的数据进行解析组拼成字符串,以流的方式发送到服务器,且上传文件用的都是POST方式,POST方式对大小没什么限制。


回到题目,可以说假设每次真的只能上传2M,那么可能我们只能把文件截断,然后分别上传了。




3、内存溢出和内存泄漏有什么区别?何时会产生内存泄漏?内存优化有哪些方法?


内存溢出通俗理解就是软件(应用)运行需要的内存,超出了它可用的最大内存。


内存泄漏就是我们对某一内存空间的使用,使用完成后没有释放。


内存优化:Android中容易内存溢出的部分,就是图片的加载,我们可以使用图片的压缩加上使用LruCache缓存的目的来控制图片所能够使用的内存。


还有对于比较耗资源的对象及时的关闭,例如Database Conn , 各种传感器 , Service 等等。




4、AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?


AsyncTask 运用的场景就是我们需要进行一些耗时的操作,耗时操作完成后更新主线程,或者在操作过程中对主线程的UI进行更新。


缺陷:AsyncTask中维护着一个长度为128的线程池,同时可以执行5个工作线程,还有一个缓冲队列,当线程池中已有128个线程,缓冲队列已满时,如果


此时向线程提交任务,将会抛出RejectedExecutionException。


解决:由一个控制线程来处理AsyncTask的调用判断线程池是否满了,如果满了则线程睡眠否则请求AsyncTask继续处理。




5、Activity用SharedPreferences保存数据,大小有木有限制?


这个真心查不到。。。




6、Activity间通过Intent传递数据大小有没有限制?


貌似是40K。




7、assest文件夹里放文件,对于文件的大小有没有限制?22


assets目录更像一个附录类型的目录,Android不会为这个目录中的文件生成ID并保存在R类当中,因此它与Android中的一些类和方法兼容度更低。


同时,由于你需要一个字符串路径来获取这个目录下的文件描述符,访问的速度会更慢。但是把一些文件放在这个目录下会使一些操作更加方便,


比方说拷贝一个数据库文件到系统内存中。要注意的是,你无法在Android XML文件中引用到assets目录下的文件,只能通过AssetManager来访问


这些文件。数据库文件和游戏数据等放在这个目录下是比较合适的。另外,网上关于assets和raw的资料都千篇一律了,因此关于这两者中单个文件


大小不能超过1M的错误描述也在传播,即如果读取超过1M的文件会报”Data exceeds UNCOMPRESSDATA_MAX (1314625 vs 1048576)”的


IOException,还引申出种种解决方案。个人认为不应该有这样的限制,为了验证这个说法写了个Demo,发现将近5M的压缩包在assets和raw中


都能正常访问,因此在这里纠正一下,理论上只要打包不超过Android APK 50M大小的限制都是没有问题的。当然了,不排除是Android很早期的


时候因为设备硬件原因aapt在编译的时候对这两个文件夹大小做出了限制,如果是这样,较新版的ADT应该不会出现这种情况。


来自:http://my.eoe.cn/futurexiong/archive/5350.html




8、 启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?


是因为启动程序(主界面也是一个app),发现了在这个程序中存在一个设置为<category android:name=”android.intent.category.LAUNCHER” />的activity,


所以这个launcher会把icon提出来,放在主界面上。当用户点击icon的时候,发出一个Intent:


Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);


mActivity.startActivity(intent);   


跳过去可以跳到任意允许的页面,如一个程序可以下载,那么真正下载的页面可能不是首页(也有可能是首页),这时还是构造一个Intent,startActivity.


这个intent中的action可能有多种view,download都有可能。系统会根据第三方程序向系统注册的功能,为你的Intent选择可以打开的程序或者页面。所以唯一的一点


不同的是从icon的点击启动的intent的action是相对单一的,从程序中跳转或者启动可能样式更多一些。本质是相同的。




9、程序之间的亲和性的理解。


1、默认情况下一个应用的所有Activity都是具有相同的affinity,都是从application中继承,application的affinity默认就是manifest的包名。


2、affinity对Activity来说,就像是身份证一样,可以告诉所在的Task,自己属于其中的一员。


3、应用场合:


a:根据affinity重新为Activity选择合适的宿主Task;


b:与allowTaskReparenting属性配合;


c:启动Activity使用Intent设置了FLAG_ACTIVITY_NEW_TASK标记。




10、同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?


可以放在不同的Task中。需要为不同的activity设置不同的affinity属性,启动activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK标记。




11、横竖屏切换时候Activity的生命周期。


1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次


2、设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次


3、设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法




12、AIDL的全称是什么?如何工作?


全称是:Android Interface Define Language


在Android中, 每个应用程序都可以有自己的进程. 在写UI应用的时候, 经常要用到Service. 在不同的进程中, 怎样传递对象呢? 显然, Java中不允许跨进程内存共享.


 因此传递对象, 只能把对象拆分成操作系统能理解的简单形式, 以达到跨界对象访问的目的. 在J2EE中,采用RMI的方式, 可以通过序列化传递对象. 在Android中, 则


采用AIDL的方式. 理论上AIDL可以传递Bundle,实际上做起来却比较麻烦。


AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要


在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用


这些参数组装成自己需要的对象.AIDL的IPC的机制和COM或CORBA类似, 是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值. 如果要使用AIDL, 


需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用aidl产生的class.


AIDL的创建方法:


AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。 由于远程调用的需要, 这些参数和返回值并不是任何类型.


下面是些AIDL支持的数据类型:


1. 不需要import声明的简单Java编程语言类型(int,boolean等)


2. String, CharSequence不需要特殊声明


3. List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型.


(另外: 我没尝试Parcelables, 在Eclipse+ADT下编译不过, 或许以后会有所支持






13、dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念



      Dvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面,每个android程序系统都会给他分配一个单独的liunx uid(user id),

每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程.












—————————————————————————-










一、面试技术01: 自定义View知识


1. View是什么?


     1). View类是所有用来构建用户界面的组件的基类


     2). ViewGroupView的一个子类是各种布局的基类


          它是包含其它ViewViewGroup和定义这些孩子布局参数的容器


     3). 一个View(ViewGroup)占用屏幕上的一个矩形区域它负责界面的绘制和事件处理


     4). 手机屏幕上所有看得见摸得着的都是View(包括ViewGroup)


 


2. View的分类


    1).  不能包含子ViewView: 一般的View


          TextView: 显示文本(它也可以带图片)


          Button: 按钮


          ImageView: 显示图片


    2). 可以包含子ViewView: ViewGroup


          FrameLayout


          RelativeLayout


          LinearLayout


          ScrollView


          ListView


          GridView


 


3. ViewGroup


     1). ViewGroup extends View implements ViewParent, ViewManager


     2). ViewManager: 用来添加、删除、更新布局


          addView(View v)


          removeView(View v)


          updateViewLayout(View v)


     3). ViewParent: 提供了一系列操作子View的方法


 


4. 关于ViewViewGroup


     1). 整个界面只会有一个根View


          a. 得到它: window.getDecorview()      PhoneWindow$decorView


          b. 本质类型: FrameLayout


          c. setContentView()添加的视图不是整个界面的根view FrameLayout(id=content)  


     2). 一个View只会有一个父View(ViewGroup), 一个ViewGroup可以有多个子View


          a. 得到父视图: view.getParent(), 可以将返回的ViewParent强转为指定的ViewGroup


          b. 不是所有的View都能添加子view, 只有ViewGroup及其子类才能添加


 


5. 区别ViewActivity?


     1). Activity是四大组件中唯一能与用户进行交互的组件


     2). Activity只是控制和管理View, 真正显示和处理事件的是View本身来完成


     3). Activity内部有一个window对象, window对象(Phonewindow)中包含一个FramLayout类型的decorView


          ActivitysetContentView(view)实质上是将view添加到decorView


          手机屏幕中显示的就decorView


 


6. 显示ContentView3种方式:


     1). setContentView(R.layout.activity_main);


     2). View view = View.inflate(this, R.layout.activity_main, null);


          setContentView(view);


     3). MyTextView tv = new MyTextView(this);


          setContentView(tv);


 


7. View的生命周期过程:


     1). 创建View对象


          a. 存在2种创建的方式加载布局文件创建和直接new构造方法创建


          b. 布局文件方式的本质解析布局xml, 根据标签名创建对应的View对象并将标签属性设置到对象中


          c. 布局文件方式在所有的View对象都创建好了后会调用onFinishInflate()


          d. 在视图对象都创建好后调用onAttachedToWindow(), 表明view对象关联到window上了


     2). 测量(多大?)


          a.方法执行: measure()—->onMeasure()—->setMeasuredDimension()


          b. measure(): 用来确定当前View的大小它是final的方法不能重写它内部调用了onMeasure()


          c.onMeasure(): 一般重写此方法根据我们的实际需求View进行测量


          d. setMeasuredDimension(): onMeasure()中必须调用些方法保存当前View测试出的宽度和高度


     3). 布局(在哪?)


          a. 方法执行: layout()—->onLayout()


          b. layout(l, t, r, b): 


               指定View的左上角点的坐标和右下角点的坐标


               比较原有的l,t,r,b与当前的l,t,r,b, 如果有变化了或请求重新layout, 就会调用onLayout(l,t,r,b)


               不会重写些方法只会调用些方法来指定当前View在父View中的位置


          c. onLayout(changed, l, t, r, b)


               决定当前view在父ViewGroup中的位置


               View类中只是空实现因为一个View的位置是由父View来指定的


               ViewGroup类中用来指定子View的位置但是abstract


                         FrameLayout


                         LinearLayout


                         RelativeLayout


               . LinearLayout的实现:


          判断自身是横屏还是竖屏?
               遍历所有的子View, 为它们准备l,t,r,b
               如果是垂直:
                    A  (0,0,width1,height1),
                    B (0,height1,width2,height1+height2),
                   C (0,height1+height2,width3,height1+height2+height3)
               如果是水平:
                    (0,0,width1,height1),
                    (height1,0,height1+width2,height2),
                    (height1+height2,0,height1+height2+width3,height3)   
          d. 可以通过requestLayout()的方式来强制重新layout
     4). 绘制(啥样?)
          a. 方法执行: draw()—->onDraw()
          b. draw(): 
               画一些通用的东西(如背景,滚动条等), 一般不会去重写此方法
                    1>. Draw the background(画背景)
                    2>. Draw view’s content(画内容)
                    3>. Draw children(画子View)
                    4>. Draw decorations scrollbars (画滚动条)
               如果是View, 使用onDraw(canvas)来画界面
               如果是ViewGroup, 使用dispatchDraw(canvas)—-分发给子View绘制
          c. onDraw(Canvas canvas)
               所有特定的View(比如:TextView/ImageView)都重写了此方法来绘制自己的样子
               主要使用PaintCanvas来绘制
          d. 可以通过调用inValidate()postInValidate()来强制重绘
     5). 事件处理
          a. 相关方法
               onTouchEvent(MotionEvent): 触摸事件的回调方法
               OnTouchListener—->onTouch(View v, MotionEvent event) : 触摸事件的监听器
          b. 事件的分发和处理过程
     6). 死亡:
          b. 相关方法: onDetachedFromWindow()
          c. Activity退出或当前View被移除触发


 


8. 总结


creation
     二种方式 : new 构造方法(context) ,  定义布局文件再加载(setContentView()/View.inflate()—-(context, AttributeSet))      全类名<TextView> <com.atguigu.MyTextView>
     所有View对象都创建好了—->onFinishInflate()[必须是布局文件]—->onAttachToWindow()  —->getViewAt(int position)
measure(多大?)
     —>measure()—->onMearsure()    产生一个测量的尺寸(宽高)  —->getMearsureHeight()  getMearsureWidth()     —>onResume()
layout(在哪?)
     —->layout(l, t, r, b)—->onLayout(boolean change, l, t, r, b)
     requestLayout(): 强制重新布局
draw(撒样?)
     draw()—->onDraw()       
     invalidate()/postInvalidate(): 强制重绘
event deal
     onTouchEvent()
          return true;  消费事件     —->拦截事件
die








     onDetachedFromWindow()


  

二、面试技术02: 自定义View应用


 


功能一快速索引列表


1. 好友列表功能:


     1). 对好友List集合按拼音首字母进行排序(需要用到pinyin4j.jar)  


     2). 显示好友列表时显示拼音首字母


2. 列表右侧AZ列表功能:


     1). 从上至下均匀显示AZ的所有字母


     2). 在按下或移动到某个字母时字体大小和颜色都有变化


     3). 在按下或移动到某个字母时正中间区域会显示当前选择的字母且过一会自动消失


     4). 在按下或移动到某个字母时列表会移动到对应的列表项区域


 


功能二滑动删除ListView的某项


         功能描述:


                  水平滑动列表的某一项可以打开或关闭


         实现过程


   1. 如何得到contentViewdeleteView对象?


       1). 重写onAttachedToWindow()


       2). 调用viewGroup.getChildAt(index)


  2. 如何得到contentViewdeleteView的宽高?


       1). 重写onMeasure()


       2). 调用getMeasuredWidth()getMeasuredHeight()


  3. 如何给contentViewdeleteView进行初始化布局定位?


       1). 重写onLayout()


       2). 调用layout()contentViewdeleteView进行布局定位


  4. 如何拖动contentViewdeleteView?


       1). 使用ViewDragHelper这个视图拖拽的帮助类


       2). 创建ViewDragHelper对象并指定其回调对象并重写其中的一些方法


            boolean tryCaptureView(View child): 判断child是否是需要拖拽的子View, down时调用


            int clampViewPositionHorizontal(): 限制view在水平方向真正移动的距离, move时调用


            onViewPositionChanged(View child): 当子view的位置发生改变时回调需要在其中去移动其它的子View


            onViewReleased(View releasedChild): 当子View被释放时回调up时调用 


            int getViewHorizontalDragRange(View child): 返回子View在水平方向最大移到的距离此方法在用于ListView时才需要重写


      3). 重写onTouchEvent(), 在其中让dragHelper对象来处理event对象


  5. 如何解决手指滑动时ListView垂直方向滚动和SwipeView水平滑动的冲突问题?


       1). move事件时获取x轴和y轴方向的移动距离distanceX, distanceY


       2). 如果distanceX>distanceY, 执行requestDisallowInterceptTouchEvent(true), 使ListView不能拦截event


  6. 如何解决SwipeView滑动与ContentView/DeleteView点击事件的冲突问题?


       1). 重写onInterceptTouchEvent()


       2). 返回dragHelper.shouldInterceptTouchEvent(ev), dragHelper来决定是否拦截event


  7. 如何只让ListView中只有一个SwipeView能被打开?


       1). SwipeView定义枚举类型状态类


       2). SwipeView中定义监听接口,在接口中定义回调方法


       3). 定义设置监听接口对象的方法


       4). ActivityAdapter中为每个SwipeView对象设置监听器对象在回调方法中做处理


  8. 如何让swipeView的自动打开和关闭是平滑的效果?


       1). 调用下面的方法打开/关闭


            dragHelper.smoothSlideViewTo(contentView, -deleteWidth, 0);


            ViewCompat.postInvalidateOnAnimation(this);


      2). 重写computeScroll()


          if (dragHelper.continueSettling(true)) {


               ViewCompat.postInvalidateOnAnimation(this);


          }                 


          9. ListView滑动时关闭打开的SwipeView   


               ListViewScroll监听中一旦滑动关闭打开的swipeView








 


三、面试技术03: View的触摸事件机制


 


1. 触摸事件的基本类型


     1). down: 按下


     2). move: 移动


     3). up: 离开


 


2. 事件对象产生的顺序


     1). down—>move—>move—>….—>up


     2). 每个事件对象产生后都会找到一个消费者来消费处理此事件


 


3. 事件相关API


     1). MotionEvent: 代表对UI的操作单元的类它的对象在用户触摸UI时系统自动创建基对象并将相关的数据保存在此对象中


ACTION_DOWN=0 : down类型值


ACTION_UP=1 : up类型值 


ACTION_MOVE=2 : move类型值 


int getAction() : 得到事件类型值


 


float getX() : 得到事件的X轴坐标(相对于当前View的左顶点)


float getRawX() : 得到事件的X轴坐标(相对于屏幕的左顶点)


float getY() : 得到事件的Y轴坐标(相对于当前View的左顶点)


float getRawY() : 得到事件的Y轴坐标(相对于屏幕的左顶点)


     2). Activity


               boolean dispatchTouchEvent(MotionEvent event) : 分发事件  


               boolean onTouchEvent(MotionEvent event) : 处理事件的回调


     3). View


               boolean dispatchTouchEvent(MotionEvent event): 分发事件


            


               setOnClickListener(OnClickListener l) : 设置触摸事件监听器对象


               private OnTouchListener mOnTouchListener; //触摸事件监听器对象变量


               public interface OnTouchListener {  //事件监听器接口


                  boolean onTouch(View v, MotionEvent event);  // 监听器对象的回调方法


               }


 


               boolean onTouchEvent(MotionEvent event)  : 事件监听回调方法


 


               setOnclickListener(OnclickListener listener) : 设置点击监听器


               setOnLongClickListener(OnLongClickListener listener) : 设置长按事件监听器


     4). ViewGroup


               boolean dispatchTouchEvent(MotionEvent ev) : 重写View的此方法如果当前ViewGroup不拦截会分发给对应的子View处理事件


               boolean onInterceptTouchEvent(MotionEvent ev) : 拦截触摸事件返回值如果为true表示拦截,后面的事件就会交给当前View来处理默认为false


               requestDisallowInterceptTouchEvent(boolean disallowIntercept) : 如果参数为true, 使当前View及其外层的所有父View不能拦截后面的事件


 


4. View的事件处理


     1). Touch事件的方法执行顺序


          . dispatchTouchEvent()


          . setOnTouchListeneronTouch()


          . onTouchEvent()


     2). 执行的详细过程


          dispatchTouchEvent()会判断是否设置了Touch监听器?


               如果没有直接进入②


               如果有调用监听器的onTouch()方法如果onTouch方法返回true到此结束如果返回false进入②


          调用onTouchEvent()


               down, send一个延时500ms的消息准备触发长按事件监听回调)


               如果0.5s内在产生了up事件此时就会移除长按的延时消息就会去执行点击事件监听回调


               如果0.5内没有产生up事件也没有离开就会调用长按事件监听回调方法如果返回的值是true就不可能再触发点击监听回调了否则还会触发.


     3). 说明:


          如果viewonTouch()(监听器回调)onTouchEvent(监听回调)down时返回true, 那第一个move事件就会交给当前View处理


               否则后面的所有事件都不会到达此View


          如是move事件处理返回true, 下一个move/up事件就会交给当前View处理,否则就会找父ViewActivity处理


          整体原则每个Event对象创建后最终肯定会有一个消费者可能是View, 也可能是ViewGroup, 实在不行就交给Activty消费处理


 


5. ViewGroup的事件处理


     1). 相关方法执行顺序:


          . dispatchTouchEvent()


          .onInterceptTouchEvent()


          对应子ViewdispatchTouchEvent()


     2). 执行的详细过程:


          dispatchTouchEvent(), ACTION_DOWN判断是否拦截,如果没有拦截,则找到包含当前x,y坐标的子View,赋值给mMotionTarget


               然后调用mMotionTarget.dispatchTouchEvent()处理down事件


          dispatchTouchEvent(), ACTION_MOVE判断是否拦截,如果没有拦截,则直接调用mMotionTarget.dispatchTouchEvent(ev)


          dispatchTouchEvent(), ACTION_UP判断是否拦截,如果没有拦截,则直接调用mMotionTarget.dispatchTouchEvent(ev)


          如果没有找到合适的子View来消费当前event, 则将自己当成View来处理event


     3). 关于拦截:


          如何拦截?: ViewGrouponInterceptTouchEvent()默认返回false, 也就是不拦截如果想拦截就重写此方法并返回true, 这样事件就不会分发给子View处理


          如何不被拦截?: 如果子View不希望父View(也就是当前ViewGroup)拦截event, View可以执行: getParent().requestDisallowInterceptTouchEvent(true)


 


6. 扩展blog:


     Android View 事件分发机制 源码解析


     Android ViewGroup事件分发机制


     


     Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

















四、面试技术04: Android中的消息机制与异步任务


 


1. 相关基础知识:


     1). Android运行的线程有两种类型: UIThread(主线程一个)WorkerThread(分线程多个)


     2). Android,只有在UIThread中才能直接更新界面如果在分线程直接更新界面会抛出如下异常:


              android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread 


              that created a view hierarchy can touch its views.


     3). Android很多长时间处理数据的工作(联网)都需要在workerThread中执行否则会抛出异常/操作反应慢


     4). 在分线程得到数据后需要去更新界面但在分线程中直接更新界面是不允许的如何解决此矛盾?


     5). 联网相关功能的三步:


          显示提示视图可能是ProgressBar, 也可能是ProgressDialog. ——在主线程执行


          请求服务器得到服务器返回的数据. ——在分线程执行


          更新界面移除提示视图显示得到的数据. ——在主线程执行


 


2. 消息机制:


     1). Android中设计的一套API和完善的运行工作体系它能解决如何情况


          分线程与主线程之间的多线程间通信


          在一个线程内工作的统一处理


          轻松实现延迟工作,  循环工作定时工作


 


     2). 相关API:


          . Message:  消息类


               Message.obtain(what) : 创建消息对象


               public int what : 标识值


               public int arg1 : 携带Int类型数据


               public int arg2 : 携带Int类型数据


               public Object obj : 携带任意对象类型数据


               public long when : 标识当前Message什么时刻应该被处理


               public Handler target : 当前message由哪个handler来分发处理


 


          . Handler: 处理器类


               sendMessage(Message msg) :   发送即时消息


               sendMessageDelayed(Message msg, long delayMillis) : 发送延时消息


               sendEmptyMessage(int what): 发送即时空消息


               sendEmptyMessageDelayed(int what, long delayMillis) : 发送延时空消息


               boolean post(Runnable r) : 发送即时带回调的空消息


               boolean postDelayed(Runnable r, long delayMillis): 发送延时带回调的空消息


 


               handleMessage(Message msg) : 处理消息的回调方法


               


               removeMessages(int what) : 根据what删除还未处理的对应消息


               removeCallbacksAndMessages(null) : 删除所有未处理的消息


               


               dispatchMessage(Message msg) : 分发消息


                         message的回调


                         handlercallback监听器的回调方法


                         handler的回调方法


          . MessageQueue: 消息队列类(我们不需要操作


               enqueueMessage(Message msg, long when): 将消息添加到消息队列


                    无论发送的是即时消息还是延时消息都是立即将message对象保存到了MessageQueue对象中


               Message next() : 取出一个需要处理的消息如果没有就会进入等待状态但不会导致UIThread阻塞      thread.wait()


          . Looper: 循环器类(我们不需要操作


               loop() : 使用无限for循环获取message, 并调用对应的handler分发处理此消息


 


     3). 原理


             


          


 


 


3. 异步任务: AsyncTask


     1). 在使用AsyncTask之前我们可以使用Handler+Thread的方式实现异步任务的功能


     2). AsyncTask的优势:


          编码上更简洁使用更方便


          效率上由于AsyncTask内部使用的是线程池能反复使用Thread对象进行分线程的处理工作而原生的方式每次都是新建Thread对象启动分线程


     3). 相关API:


class AsyncTask<Params, Progress, Result>


     Params 启动任务执行的输入参数,比如HTTP请求的URL


     Progress 后台任务执行的百分比。


     Result 后台执行任务最终返回的结果,比如String


execute(Params… params) : 


     启动任务开始任务的执行流程


void onPreExecute() : 


     在分线程工作开始之前在UIThread中执行,一般用来显示提示视图


Result doInBackground(Params… params) : 


     workerThread中执行完成任务的主要工作,通常需要较长的时间


void onPostExecute(Result result)   


     doInBackground()执行完后在UIThread中执行,一般用来更新界面 


publishProgress(Progress… values) :


     在分线程中发布当前进度


void onProgressUpdate(Progress… values) : 


     在主线程中更新进度


     4). 原理:


          execute()








          










五、面试技术05ListView


 


0. 0不优化:


     每次执行getView(), 都会执行:  converterView = View.inflate(R.layout.xxx);


     问题效率太低在快速滑动时会有卡顿在数据很多时甚至会内存溢出


 


1. 第一层复用converterView


     if(converterView==null) {


          converterView = View.inflate(R.layout.xxx);  10—>11


     }


     问题每次执行getView()都需要执行converterView.findViewById()得到子View


 


2. 第二层使用ViewHolder, 减少findViewById()的次数


     Viewholder holder = null;


     if(converterView==null) {


          converterView = View.inflate(R.layout.xxx);


          holder = new ViewHolder();


          holder.imageView = (ImageView)converterView.findViewById(xxx);


          holder.textView = (TextView)converterView.findViewById(yyy);


          converterView.setTag(holder);


     } else {


          holder = (Viewholder )converterView.getTag();


     }


 


     static class ViewHolder {


          ImageView imageView;


          TextView textView;


     }


 


     问题1: 对于联网获取列表数据如果数据量太大(比如超过100条甚至更多), 一次获取出来显示太慢太耗流量


     问题2: 对于联网获取列表数据如果包含图片数据每次都请求获取显示太慢太耗流量


 


3. 第三层对数据列表进行分页加载显示


     1). 自己做通过Scroll监听listView.setonScrollListener(scrollListener), 当到达底部时加载下一页列表数据并显示


     2). 使用第三方开源框架: Android-PullToRefresh或其它


 


4. 第四层优化图片三级缓存处理








     
参见图片三级缓存机制










六、面试技术06: 图片的三级缓存机制


 


1. 什么是三级缓存?


          一级内存中的缓存图片对象(Bitmap), Map<url, Bitmap>


          二级手机sd卡的files或手机内部的files中缓存图片文件(xxx.jpg/png)
          三级服务器端保存图片文件


 


2. 如何应用三级缓存?


          例如如何根据url根据图片显示?


          1). 根据url从一级缓存(Map<url, Bitmap>)中取图片对象如果取到了直接显示


                    注意真实项目中使用LruCache<String, Bitmap>来缓存图片(查看<<面试技术11. 图片处理优化>>)


          2). 如果没有根据url中包含图片名称(文件名), 手机的sd卡或内部找对就图片文件加载成bitmap
                    如果找到了显示并保存到一级缓存
          3). 如果没有显示一个默认的图片根据url联网请求获取bitmap
                    如果没有显示一张代表错误的图片
                    如果有:
                         a. 保存到一级缓存
                         b. 保存到二级缓存
                         c. 显示图片


 


3. ListView中应用图片三级缓存的问题?


     问题


          1). 在快速滑动时会出现显示错误图片   


          2). 图片显示后过一会又会变为另一张图片(图片闪动)


     原因:


           在分线程加载图片的过程中, converterView已经被复用


     解决:


          1). url字符串保存到imageView对象的tag


          2. 在加载图片的线程开始干活前查看imageViewtag中的url是否变化如果变化不加载图片








          3). 
在加载到图片准备显示前

再次查看
imageView

tag
中的
url
是否变化

如果变化不显示图片










七、面试技术07: Android的四大应用组件


 


1. Android的四大应用组件是哪些?


     1). Activity


     2). Service


     3). BroadcastReceiver


     4). ContentProvider


 


2. 对应用组件的理解


     1). Java是面向对象的Android是面向组件的(包括应用组件与视图组件), 我们在写项目时都是从写各种组件类开始的


     2). 作为应用组件都会有一些特点:


          都需要继承系统定义好的某个组件类


          需要进行注册(配置文件/代码)


          对象的创建和管理都是由系统帮我们完成


          都有一定的生命周期方法我们要去实现或重写它们来做一些我们的工作 


 


3. 对各个应用组件的理解


     1). Activity: 活动


          描述提供能与用户进行交互的用户界面


          主要工作加载布局为视图设置监听在监听回调中完成工作


                         利用Activity的生命周期回调方法做一些特定的工作


           重要知识点:命周期方生法, launchMode, BackStack, Activity的启动与停止


     2). Service: 服务


          描述后台为应用做一些时间跨度比较大的任务      长时间的任务


          区别: ServiceActivity, ServiceThread


          重要知识点: Service的生命周期


   


     3). BroadcastReceiver: 广播接收器


          描述广播机制是Android中实现不同应用间(进程间)通信的一种手段(应用级的事件机制)


          重要知识点区别注册接收器的两种方式


                            区别一般广播与有序广播


                            常见的系统广播 


     4). ContentProvider: 内容提供者


            描述用来将当前应用表数据的操作暴露给其它应用


            重要知识点为什么要用ContentProvider?


                              ContentResolver, ContentProviderContentObsolver的关系


 


     注意每个都可以说一个项目中的例子来说明


 


 


























 








  - 2. SharedPrefrence存储






  1). 位置


  data/data/应用的包名/shared-prefs/xxx.xml中


  2). 特点






  1.存储的都是一些小的变量。


 
类型为:boolean float int long String


  2. 存储的是键值对特点的数据。而且key都为String型,value即为以上的五种类型。


 
要求存储的数据的key是不相同的。


  3.随着应用的卸载而被删除


  4.数据可以设置为私有的,只能被当前应用访问。






  3). 相关API






















- 3. 手机内部文件存储






  1). 位置


  data/data/应用的包名/files/xxx


  2). 特点






 
1.存储的文件没有大小的限制。(不能超出存储空间大小)


  2.可以存储任何格式的文件.(. png .doc .txt .mp3)


 
3.会随着应用的卸载被删除


  4.可以将此目录下的文件设置为私有的。






  3). 相关API










- 4. 手机外部文件存储(sd卡的存储)






  1). 位置


  路径1:storage/sdcard/Android/data/应用的包名/files/xxx


  路径2:storage/sdcard/xxx


  2). 特点






1.路径一中保存的数据会随着应用的卸载被删除


  路径二中保存的数据不会随着应用的卸载被删除


2.存储在此路径下的文件是公共的


3.可以存储任意类型的文件


4.文件的大小没有限制,只要不超过sd卡的存储空间即可


5.权限:android.permission.WRITE_EXTERNAL_STORAGE






  3). 相关API










比较内部文件与外部文件存储?






>文件不大,访问较为频繁,比较重要=>手机内部存储


>数据如果是私有的,不希望其它应用访问,考虑使用手机内部存储


>是否需要随着应用的卸载而被删除。不需要,使用手机外部存储的路径2的方式








  • 6. 远程服务器存储




1). 存储的位置


    >存储在远程的服务器端










2). 特点


     >相较于前面的4种存储方式,远程服务器的存储不保存在本地


     >不会随着应用的卸载,而被删除










3). 实现联网请求的技术


    






1)  使用的是Java提供的API:HttpURLConnection


     1.要访问资源的路径:  GET请求: http://192.168.10.165:8080/Web_server/index.jsp?username=Tom&age=10


                                          POST请求:http://192.168.10.165:8080/Web_server/index.jsp


     2. URL url = new URL(path)


     3.获取连接对象: HttpURLConnection conn = url.openConnection();


     4.设置参数:  conn.setConnectionTimeout();  conn.setReadTimeout(); 请求方法:setRequestMethod(); setDoInput();setDoOutput()


              如果是POST请求,需要填充请求参数:


               conn.getOutputStream().write(byte[]);


     5.连接:  conn.connect();


     6.获取响应码: conn.getResponseCode() == 200   404 500


     7.获取服务器端发送过来的数据:  conn.getInputStream()      BitmapFactory.decode(InputStream is)


     8.资源的关闭:流的关闭,连接的关闭:conn.disconnect();










2) android内置的API:HttpClient


    1.创建了一个客户端的对象: DefaultHttpClient


    2.设置请求参数: HttpConnectionParams


    3.提供一个GET请求的对象/ POST请求的对象: (包含请求路径)


               GET请求: http://192.168.10.165:8080/Web_server/index.jsp?username=Tom&age=10


                POST请求:http://192.168.10.165:8080/Web_server/index.jsp


              GET请求: new HttpGet(path)


               POST请求: new HttpPost(path);   设置请求体:  httpPost.setEntity();


    4.  得到HttpResponse :  client.execute(httpGet/ httpPost)


    5.  获取响应状态行中的响应码:httpResponse.getStatusLine() .getStatusCode()


    6.  获取包含响应数据的entity :  httpResponse.getEntity()


    7. 解析数据: EntityUtils.toString(entity,charset)


    8. 使用响应数据


    9.资源的关闭: client.getConnectionManager.shutDown();






3 ) 第三方框架:Volley / XUtils


     1. 创建一个RequestQueue  (先进先出的特点)


     2. 创建请求对象: StringRequest/JsonRequest/ImageRequest   (重写 onResponse(String result ) / onErrorResponse())


               如果是一个POST请求,还需要重写getParams(),返回一个包含请求数据的map即可。



     3.将请求对象添加到队列里: queue.add(request);










九、面试技术09: 性能优化


 


1. 性能相关的两个概念


     1). 响应时间


          指从用户操作开始到系统给用户以正确反馈的时间


          系统处理时间 网络传输时间(可能没有) + 展现时间


     2). TPS(Transactions Per Second)


          每秒处理的事务数是系统吞吐量的一个指标


 


2. 什么是性能问题?


     响应时间过长系统吞吐量过低高并发下内存泄漏  (ANR)


 


3. 性能调优的方式:     


     1). 降低执行时间


              缓存(对象缓存,IO缓存网络缓存, DB缓存)


               数据存储类型优化


               算法优化


               逻辑优化


               JNI


               需求优化


     2). 同步改异步


               利用多线程提高TPS


     3). 提前或延迟操作


              错开时间段提高TPS


 


4. 调优点:


     1). Java代码部分优化


     2). 布局优化、


     3). 数据库优化 


 


5. Java代码优化之缓存优化:


     1). 线程池


     2). 图片缓存


     3). Message缓存


     4). ListView缓存


     5). layout缓存


     6). 文件IO缓存


 


6. Java代码优化之数据存储优化


     1). 数据类型选择:


          StringBuilder/StringBuffer代替String


          SoftRefrence代替强引用


          LocalBroadcastManager代替普通BroadcastReceiver,效率和安全性都更高


     2). 数据结构选择


          ArrayListLinkedList的选择


          ListMap的选择


          Android中推荐用SparseArray代替Map<Integer,Object>, SparseArray内部使用二分法查找数据效率更高


 


7. Java代码优化之算法优化


     查询考虑hash和二分,尽量不用递归


     必要时可以考虑使用空间换时间


 


8. 逻辑优化


     主要是理清程序逻辑,减少不必要的操作。


 


9. 异步,利用多线程提高TPS


     充分利用多核Cpu优势,利用线程解决密集型计算、IO、网络等操作分线程处理完成后可以通过Handler与主线程交互


 


10. 提前或延迟操作,错开时间段提高TPS


     1) 延迟操作不在ActivityServiceBroadcastReceiver的生命周期等对响应时间敏感函数中执行耗时操作,可适当delay


     2). 提前操作对于第一次调用较耗时操作,可统一放到初始化中,将耗时提前


 


11. 网络优化


a. 图片必须缓存,最好根据机型做图片做图片适配


b. 所有http请求必须添加httptimeout
c. 开启gzip压缩
d. api接口数据以json格式返回,而不是xmlhtml
e. 根据http头信息中的Cache-Controlexpires域确定是否缓存请求结果。
f. 确定网络请求的connection是否keep-alive
g. 减少网络请求次数,服务器端适当做请求合并。
h. 减少重定向次数


i. api接口服务器端响应时间不超过100ms


 


12. 布局优化:


     1). 对于布局的选择: FrameLayout>RelativeLayout>LinearLayout


     2). <include>标签


     3). <viewstub>标签


     4). <merge>标签


     5). 去除不必要的嵌套和View节点


     6). 减少不必要的infalte, infalte布局后缓存起来








     7). 
多使用布局调优工具来查看布局情况并做出合理的优化










十、面试技术10. 内存溢出与内存泄露


 


1. 定义


     1). 内存溢出即为out of memory, 当你要求分配的内存超过了系统给你的内存时


                  系统就会抛出out of memory的异常(每个Android能用的内存是有限的)


                  比如当前应用只剩下4M的空间可用但你却加载得到一个需要占用5M空间的图片Bitmap对象就会抛出溢出的异常


     2). 内存泄露即为memory leak, 一个对象被创建后你不再使用它了但因为某种原因它又没有成为垃圾对象这块内存不能再被分配置使用


                  比如查询数据库得到的cursor对象在使用完后没有关闭, Activity中使用Handler发延迟消息但退出前不移除未处理的消息


     3). 内存泄露不多时没有太大影响但积累得多了就会导致应用运动缓慢到最后就会内存溢出


 


2. 内存泄漏的分类:


     1). 常发性内存泄漏发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏


     2). 偶发性内存泄漏发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。


                        对于特定的环境,偶发性的也许就变成了常发性的


     3). 一次性内存泄漏发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏


     说明危害性大小顺序为:  1)>2)>3)


 


3. 造成内存泄露的几种场景


       1). 长生命周期的对象持有短生命周期对象的引用:  Activity中使用Handler


       2). 资源数据连接相关对象不关闭: cusor, stream, connection


       3). HashSet中的对象或HashMap中的Key对象基内部与hash值相关的属性被修改


       4). 一些对象产生后不会自动释放或需要完全执行完了才释放比如: Bitmap, Thread, AsyncTask


 


4. 避免内存泄露


1). 尽早释放无用对象的引用


2). 使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域


3). 尽量少用静态变量,因为静态变量存放在永久代(方法区),永久代基本不参与垃圾回收


4). 避免在循环中创建对象


 


5. 造成内存溢出的的场景:


       1). 申请了太多的对象比如使用ListView不复用convertView, 当数据项多时就会出现内存溢出


       2). 创建的对象内存太大比如不经过压缩直接加载大图片文件


       3). 内存泄露积累一定的时间后就可能出现


 


6. 避免内存溢出:


      1). 通过复用对象的方式减少产生的对象


      2). 大对象需要先压缩后创建


      3). 避免或减少内存泄露的情况


 


注意


     双击全屏查看








     
自己也多百度一下看看多积累








 
十一、面试技术11. 图片处理优化










1. 大图片的加载显示(避免OOM问题):






  1). 问题: 如果将大图片加载到内存中来显示, 可能会导致内存溢出(OOM)






  2). 解决思路: 对图片进行压缩加载(本质上只是读取了图片文件的部分数据)






  3). 具体办法:






  ①. 得到图片的宽高的方式:






BitmapFactory.Options options = new BitmapFactory.Options();






options.inJustDecodeBounds = true; //设置只读取图片文件的边框,这样就不会加载整个图片文件






BitmapFactory.decodeResource(getResources(), R.id.myimage, options);






int imageHeight = options.outHeight; //图片的高






int imageWidth = options.outWidth; //图片的宽






String imageType = options.outMimeType;






  注意: 为了避免OOM异常,最好在解析每张图片的时候都先检查一下图片的大小,






  除非你非常信任图片的来源,保证这些图片都不会超出你程序的可用内存






  ②. 计算取样比例的方式:






public static int calculateInSampleSize(BitmapFactory.Options options,






  int reqWidth, int reqHeight) {






  // 源图片的高度和宽度






  final int height = options.outHeight;






  final int width = options.outWidth;






  int inSampleSize = 1;






  if (height > reqHeight || width > reqWidth) {






  // 计算出实际宽高和目标宽高的比率






  final int heightRatio = Math.round((float) height / (float) reqHeight);






  final int widthRatio = Math.round((float) width / (float) reqWidth);






  // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高






  // 一定都会大于等于目标的宽和高。






  inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;






  }






  return inSampleSize;






}






  注意: 如果inSampleSize=3, 表示 宽和高上只读取原来数据的1/3, 这样整体大小压缩为原来的1/9






  ③. 整体处理:






public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,






  int reqWidth, int reqHeight) {






  // 第一次解析将inJustDecodeBounds设置为true,只获取图片宽,高大小






  final BitmapFactory.Options options = new BitmapFactory.Options();






  options.inJustDecodeBounds = true; //不会加载整个图片文件






  BitmapFactory.decodeResource(res, resId, options);






  // 调用上面定义的方法计算inSampleSize值






  options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);






  // 使用获取到的inSampleSize值再次解析图片






  options.inJustDecodeBounds = false; //会根据inSampleSize加载图片的部分数据到内存






  return BitmapFactory.decodeResource(res, resId, options);






}






  调用代码如下:






mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));






//将任意一张图片压缩成100100的缩略图,并在ImageView上展示














2. 缓存图片对象






  1). 在内存中缓存图片对象(Bitmap), 不要直接用Map<String, Bitmap>类型的容器, 因为这样会导致bitmap对象太多太大时而没有去释放, 最终导致OOM






  2). 在Android2.3之前, 一般都用Map<String, SoftReference<Bitmap>>结构容器来缓存Bitmap对象, 这样在内存不太充足时, 垃圾回收器会将软引用对象释放.






  但从2.3开始, 垃圾回收器可能在正常情况下就回收软引用对象, 这样会降低缓存的效果






  3). Android的v4兼容包中提供了LruCache来做缓存容器, 它的基本原理为:






  把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除










private LruCache<String, Bitmap> mMemoryCache; //缓存Bitmap的容器










@Override






protected void onCreate(Bundle savedInstanceState) {






  // 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。






  // LruCache通过构造函数传入缓存值,以KB为单位。






  int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);






  // 使用最大可用内存值的1/8作为缓存的大小。






  int cacheSize = maxMemory / 8;






  mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {






  @Override






  protected int sizeOf(String key, Bitmap bitmap) {






  // 重写此方法来衡量每张图片的大小,默认返回图片数量。






  return bitmap.getByteCount() / 1024;






  }






  };






}










public void addBitmapToMemoryCache(String key, Bitmap bitmap) {






  if (getBitmapFromMemCache(key) == null) {






  mMemoryCache.put(key, bitmap);






  }






}










public Bitmap getBitmapFromMemCache(String key) {






  return mMemoryCache.get(key);






}














3. 主动释放bitmap对象






if(!bmp.isRecycle() ){ bmp.recycle() // 回收图片所占的内存 system.gc() // 提醒系统及时回收}














4. 设置加载图片的色彩模式:






  Android中有四种,分别是:






ALPHA_8:每个像素占用1byte内存






ARGB_4444:每个像素占用2byte内存






ARGB_8888:每个像素占用4byte内存(默认)






RGB_565:每个像素占用2byte内存






  默认的模式显示的图片质量是最高的, 但也是占用内存最大的, 而如果使用ARGB_4444模式, 占用的内存就会减少为1/2, 但显示效果差别不明显






BitmapFactory.Options options = new BitmapFactory.Options();






options.inPreferredConfig = Bitmap.Config.ARGB_4444;






Bitmap img = BitmapFactory.decodeFile(”/sdcard/1.png”, options);














5. 相关优秀Blog










 












十二、面试技术12. 单例模式与工厂模式







1. 
单例模式


     1). 
懒汉式


          


     2). 
饿汉式


          






2. 
工厂模式


     1).
简单工厂


          


     2).
工厂方法模式与抽象工厂模式: 可以在网上找找了解一下就可以了


     















  










十三、面试技术13. 常用的三种排序算法


1. 冒泡排序


     1)基本思想:


          在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,


          让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。


     2). 实例:


          


     3). 代码实现:


          


 


2. 选择排序


     1). 基本思想:


          在要排序的一组数中,选出最小的一个数与第一个位置的数交换;


          然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。


     2). 实例:


          


     3). 代码实现:


          


          


 


3. 插入排序


     1). 基本思想:


          在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,


          使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。


     2). 实例:


          


     3). 代码实现:


          


 








 






十四、面试技术14. 常用的几种数据结构


 


1. 数组(Array)与链表(Link)的区别:


     1). 都是内存真实的数据存储结构


     2). 数据结构特点:


          数组是一块连续的内存通过下标来索引数组中的某个元素数据


          链表并不是一块连续的内存黄区域它是通过链表中的一个元素对象保持着下一个元素对象的引用来关联的


     3). 创建结构对象:


          数组必须指定初始化大小,而且不能自动扩容


          链表不用指定大小它的大小是操作元素对象时动态产生的


     4). 添加/删除数据


          数组在添加/删除时很可能导致移动复制拷贝的问题效率不太高


          链表在添加/删除时只需要修改引用就可以效率很高


     5). 查询


          数组是通过下标来得到对应位置的数据的


          链表只能通过从一端开始查找的方式获取数据


 


2. 队列(Queue)与栈(Stack)的区别:


     1). 都是根据数组或链表来定义出的抽象数据结构


     2). 队列先进先出,栈先进后出


     3). 对插入和删除操作的限定“ 


          栈是限定只能在表的一端进行插入和删除操作的线性表。      


          队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。


     


     面试官:队列和栈有什么区别?


     程序员:吃多了拉就是队列吃多了吐就是栈.








 










十五、面试技术15. RAMROM


 


1). RAM: Random Access Memory : 随机存取存储器运行时内存


     可以在RAM中对数据进行直接的读写操作(CRUD)


     存取速度较快


     停止运行后内存中的数据就会被清理


     Android应用程序就是在RAM中运行的


 


2). ROM: Read Only Memory: 只读存储器


     可以在ROM中保存和读取数据但不能直接更新如果需要更新得先将数据加载到RAM中进行更新后写入ROM


     存取速度较慢


     停止运行/断电后信息不丢失


     Android的系统文件, APK安装文件等文件都是保存在ROM(SD卡不是ROM)


 


3). 例子: Moto XROMRAM数据


      


 


 


 


十六、面试技术16: Android中的进程与线程


 


1. 基本知识:


     如果某个应用程序组件是第一次被启动,且这时应用程序也没有其他组件在运行,则Android系统会为应用程序创建一个包含单个线程的linux进程。默认情况下,同一个应用程序的所有组件都运行在同一个进程和线程里(叫做“main”主线程)。如果组件启动时,已经存在应用程序的进程了(因为应用程序的其它组件已经在运行了),则此组件会在已有的进程和线程中启动运行。不过,可以指定组件运行在其他进程里,也可以为任何进程创建额外的线程。


 


2. 进程的分类(根据进程的重要性从高到低)和生命周期


     1). 前台进程


          用户当前操作所必须的进程。满足以下任一条件时,进程被视作处于前台:


               o其中运行着正与用户交互的ActivityActivity对象的 onResume() 方法已被调用)。


               o其中运行着被正与用户交互的activity绑定的服务Service


               o 其中运行着“前台”服务Service——服务以startForeground()方式被调用。


               o其中运行着正在执行生命周期回调方法(onCreate()onStart()onDestroy())的服务Service


               o其中运行着正在执行onReceive()方法的BroadcastReceiver


          绝大情况下不会终止此类进程当内存不足以维持它们同时运行时——才会被终止


     2). 可见进程


          没有前台组件、但仍会影响用户在屏幕上所见内容的进程


               o 其中运行着不在前台的Activity,但用户仍然可见到此activityonPause()方法被调用了)


               o 其中运行着被可见(或前台)activity绑定的服务Service


          可见进程被认为是非常重要的进程,除非无法维持所有前台进程同时运行了,它们是不会被终止的。


     3). 服务进程


          此进程运行着由startService()方法启动的服务


          除非内存不足以维持所有前台、可见进程同时运行,系统会保持服务进程的运行。


     4). 后台进程


          包含目前用户不可见activityActivity对象的onStop()方法已被调用)的进程


          这些进程对用户体验没有直接的影响,系统可能在任意时间终止它们,以回收内存供前台进程、可见进程及服务进程使用


     5). 空进程


          不含任何活动应用程序组件的进程


          保留这种进程的唯一目的就是用作缓存,以改善下次在此进程中运行组件的启动时间。


        为了在进程缓存和内核缓存间平衡系统整体资源,系统经常会终止这种进程


3. 关于线程


     1). 应用程序启动时,系统会为它创建一个名为“main”的主线程也称为“UI Thread”


     2). UI Thread特点重要组件的回调方法事件的分发和回调, UI的更新都是在线程执行的


     3). 一些长时间的工作(如联网)不能在UI Thread中执行只能在分线程(worker Thread)中执行








 














十七、面试技术17:JSON


 


1. 什么是JSON?


     1. JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式


     2. 本质就是具有特定格式的字符串


     3. JSON数据已经是客户端与服务器端交互的最常用的选择已经很少使用xml来进行数据交互了


 


2. 格式


     整体结构:


          Json数组 :  [ ]


          Json对象: {  }


     . Json数组的结构: [value1, value2, value3]


     . Json对象的结构: {key1:value1, key2:value2, key3:value3}


     . key的数据类型字符串


     . value的数据类型


               数值


               字符串


               null


               json数组


               json对象


     例子:


          [{“name”:”tom”}]: 


          [“name”:”tom”]: 不对


          {“name”:”Tom”, ”age”:12}: 


          {“name”:”Tom”, ”age”:12, 23}: 不对


 


3. 解析:


     解析技术


          1). Android原生API: 编码麻烦


          2). Gson框架解析更方便更高效


     解析方向:


          1). java对象(包含集合)转换为json格式字符串) [一般在服务器端用]


          2). json格式字符串转换为java对象(包含集合) [一般在客户端用]


 


4. 比较json相对于xml的优势


     同一数据量使用json表达更小这样能省流量响应速度更快








     


解析
json
数据

编码更方便

效率更高














十八、面试技术18: ANR


 


理解:


     Application Not Responding(应用没有响应)


 


原因


     程序在UI线程中对用户的操作响应执行的时间过长


 


 


具体原因分类:


     按键或触摸事件在特定时间内无响应(大概5S在上)


     BroadcastReceiver在特定时间内无法处理完成(大概10S以上)


     Service在特定的时间内无法处理完成(大概20S以上)


 


解决


     不要在UI线程中做长时间的事


     耗时的操作放入单独的线程中处理


     服务和广播接收器的生命周期回调方法都是UI线程中执行


 


九、面试技术20_Android开发中的MVC模式


1. 什么是MVC?


     1). 软件工程中的一种软件架构全称为“Mode—View—Controller”, 即为模型视图控制器


      2). MVC将交互式的应用程序分为3个组件:


          ①. Mode(模型) : 模型层包括实体模型与业务模型主要作用是完成业务逻辑处理和数据封装


                                   在Android对应实体类/业务类/DAO


          ②. View(视图) : 显示层(表示层), 向用户显示信息


                                   在Android对应布局和自定义控件类


          ③. Controller(控制器) : 控制层处理用户输入并实现View层与Mode层的协同处理


                                   在Android对应Activity


2. 理解MVC


     1). 基本结构图


 


     


     2). Android中的MVC结构:


        ①. M模型层


               com.atguigu.ms.bean: 实体类包


               com.atguigu.ms.utils: 工具包(简单的业务逻辑处理)


               com.atgiugu.ms.dao: 数据库操作


               com.atguigu.ms.net: 网络请求


          ②. V视图层:


               res下的layout, drawable, values


               自定义View


          ③. C控制层:


               Activity


               其它应用组件


3. 使用MVC模式的好处 /如果不用MVC会有什么问题?


     1). 如果不用View(布局)?


          问题每个Activity都需要创建整个布局视图对象一个是代码量更大


另一个不易实现复用(布局是可以轻松实现复用的), 还有就是修改更麻烦 


     2). 如果不用Mode(实体Mode)?


          问题当应用一个界面需要展示或处理很多数据时对应的实体类是必不可少的


     3). 如果不用Mode(非实体Mode)?


          问题那需要将所有的逻辑处理的代码都写到Activity一个使Activity变得太臃肿


另一个无法复用业务逻辑功能代码












十、面试技术01技术站点


1. 需要关注的技术网站


     https://github.com/ : 开源项目托管中心, 开源项目集中营


          https://github.com/xfzhang : 张晓飞老师的github


          https://github.com/zxfjd3g/android-open-project : 开源项目分类列表


     http://stackoverflow.com/  : 国外知名分类问答网站


     http://www.csdn.net/ : CSDN(汇集众多牛人博客)


     http://www.eoeandroid.com/ : eoe安卓社区


     http://www.apkbus.com/ : 安卓巴士


     http://www.oschina.net/  : 开源中国社区


     http://www.23code.com/  : Android经典开源项目收集站点


 


2. 不错的个人博客站点


        http://www.trinea.cn/


        http://stormzhang.com/


http://blog.csdn.net/xiaanming


http://blog.csdn.net/guolin_blog


http://blog.csdn.net/lmj623565791/article/list/1


http://blog.csdn.net/singwhatiwanna


http://blog.csdn.net/bboyfeiyu


http://blog.csdn.net/aigestudio


http://blog.csdn.net/hellogv


http://blog.csdn.net/xyz_lmn







发表评论

表情:
评论列表 (有 0 条评论,106人围观)

还没有评论,来说两句吧...

相关阅读