Android面试题(2016)luckyboy

总结了一下百度出来的近期android面试题目,有的自己总结的,有的拷贝出来的,希望对大家有帮助偷笑

J2EE 部分:

  1. Switch能否用string做参数?

    1.  Java  之前, switch 只能支持byte,short,char,int 或者其对应的封装类以及 Enum 类型。在JAVA 7中,String 支持被加上了。   

  2. equals与==的区别:

    1. ==是判断两个变量或实例是不是指向同一个内存空间 
      equals是判断两个变量或实例所指向的内存空间的值是不是相同 

  3. Object有哪些公用方法?

    1. 方法equals测试的是两个对象是否相等

    2. 方法clone进行对象拷贝

    3. 方法getClass返回和当前对象相关的Class对象

    4. 方法notify,notifyall,wait都是用来对给定对象进行线程同步的

  4. Java的四种引用,强弱软虚,用到的场景

    1. 强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象

    2. 软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。

    3. 弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象

    4. 虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。

    5. 使用场景:

      1. 利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题

      2. 通过软可及对象重获方法实现Java对象的高速缓存:比如我们创建了一Employee的类,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。我们可以通过软引用和 HashMap 的结合,先是保存引用方面:以软引用的方式对一个Employee对象的实例进行引用并保存该引用到HashMap 上,key 为此雇员的 id,value为这个对象的软引用,另一方面是取出引用,缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,并保存对这个新建实例的软引用

  5. Hashcode的作用,与 equal 有什么区别

    1. 同样用于鉴定2个对象是否相等的,java集合中有 list 和 set 两类,其中 set不允许元素重复实现,那个这个不允许重复实现的方法,如果用 equal 去比较的话,如果存在1000个元素,你 new 一个新的元素出来,需要去调用1000次 equal 去逐个和他们比较是否是同一个对象,这样会大大降低效率。hashcode实际上是返回对象的存储地址,如果这个位置上没有元素,就把元素直接存储在上面,如果这个位置上已经存在元素,这个时候才去调用equal方法与新元素进行比较,相同的话就不存了,散列到其他地址上

  6. String、StringBuffer与StringBuilder的区别

    1. String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象

    2. StringBuffer和StringBuilder底层是 char[]数组实现的

    3. StringBuffer是线程安全的,而StringBuilder是线程不安全的


  7. Override和Overload的含义去区别

    1. Overload顾名思义是重新加载,它可以表现类的多态性,可以是函数里面可以有相同的函数名但是参数名、返回值、类型不能相同;或者说可以改变参数、类型、返回值但是函数名字依然不变。

    2. 就是ride(重写)的意思,在子类继承父类的时候子类中可以定义某方法与其父类有相同的名称和参数,当子类在调用这一函数时自动调用子类的方法,而父类相当于被覆盖(重写)了。

  8. 抽象类和接口的区别

    1. 一个类只能继承单个类,但是可以实现多个接口

    2. 接口强调特定功能的实现,而抽象类强调所属关系

    3. 抽象类中的所有方法并不一定要是抽象的,你可以选择在抽象类中实现一些基本的方法。而接口要求所有的方法都必须是抽象的

  9. 解析XML的几种方式的原理与特点:DOM、SAX、PULL

    1. DOM:消耗内存:先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。这个写起来很简单,但是很消耗内存。要是数据过大,手机不够牛逼,可能手机直接死机

    2. SAX:解析效率高,占用内存少,基于事件驱动的:更加简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。

    3. SAX:与 SAX 类似,也是基于事件驱动,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。

  10. wait()和sleep()的区别

    1. sleep来自Thread类,和wait来自Object类

    2. 调用sleep()方法的过程中,线程不会释放对象锁。而 调用 wait 方法线程会释放对象锁

    3. sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU

    4. sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒

  11. JAVA 中堆和栈的区别,说下java 的内存机制

    1. 基本数据类型比变量和对象的引用都是在栈分配的

    2. 堆内存用来存放由new创建的对象和数组

    3. 类变量(static修饰的变量),程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中

    4. 实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的"物理位置”,实例变量的生命周期--当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存

    5. 局部变量: 由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放

  12. JAVA多态的实现原理 

    1. 抽象的来讲,多态的意思就是同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

    2. 实现的原理是动态绑定,程序调用的方法在运行期才动态绑定,追溯源码可以发现,JVM 通过参数的自动转型来找到合适的办法。

  13. JAVA 垃圾回收机制

    1. 什么是垃圾回收机:释放那些不再持有引用的对象的内存

    2. 怎么判断一个对象是否需要收集?

      1. 引用计数(最简单古老的方法):指将资源(可以是对象内存磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程

      2. 对象引用遍历(现在大多数 jvm 使用的方法):对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集

    3. 几种垃圾回收机制 

      1. 标记回收法:遍历对象图并且记录可到达的对象,以便删除不可到达的对象,一般使用单线程工作并且可能产生内存碎片

      2. 标记-压缩回收法:前期与第一种方法相同,只是多了一步,将所有的存活对象压缩到内存的一端,这样内存碎片就可以合成一大块可再利用的内存区域,提高了内存利用率

      3. 复制回收法:把现有内存空间分成两部分,gc运行时,它把可到达对象复制到另一半空间,再清空正在使用的空间的全部对象。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。 

      4. 分代回收发:把内存空间分为两个或者多个域,如年轻代和老年代,年轻代的特点是对象会很快被回收,因此在年轻代使用效率比较高的算法。当一个对象经过几次回收后依然存活,对象就会被放入称为老年的内存空间,老年代则采取标记-压缩算法

  14. 讲讲 Java 中的集合有多少种,区别是什么?

    1. ArrayList、LinkedList、Vector的区别:ArrayList 和Vector底层是采用数组方式存储数据,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,随机存取比较慢

    2. HashMap的底层源码实现:当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

    3. Fail-Fast机制:在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast机制。这一机制在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map.

    4. HashMap和 HashTable 的区别:

      1. HashTable比较老,是基于Dictionary 类实现的,HashTable 则是基于 Map接口实现的

      2. HashTable 是线程安全的, HashMap 则是线程不安全的

      3. HashMap可以让你将空值作为一个表的条目的key或value



Android部分:

  1. 注册广播有哪几种方式,有什么区别?答:

    1、在应用程序的代码中注册

    注册BroadcastReceiver:

    registerReceiver(receiver,filter);

    取消注册BroadcastReceiver:

    unregisterReceiver(receiver);

    当BroadcastReceiver更新UI,通常会使用这样的方法注册。启动Activity时候注册BroadcastReceiver,Activity不可见时候,取消注册。

    2、在androidmanifest.xml当中注册

    <receiver>

        <intent-filter>

         <action android:name = "android.intent.action.PICK"/>

        </intent-filter>

    </receiver>

     

    1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。

    2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

  2. 绘制 Activity 的生命流程图?答:   

    1.启动Activity:系统会先调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。

    2.当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。

    3.当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。

    4.当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。

    5.用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。

    6.当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。

    7.用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity。

    3.注册Service需要注意什么?答:Android是单线程模型,这意味着Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,所以你单纯的new一个Thrad并且start()不行的,因为这违背了Android的单线程模型。
    很幸运的是Android为我们提供了在其他线程中访问UI线程的方法,相信大家都见过,这几个就是Activity的runOnUiThread方法,View的post和postDelayed方法,以及最常用的Hanlder和AsyncTask,这里我推荐使用Hanlder和AsyncTask,尤其是AsyncTask,因为使用他们你会发现你的代码很容易被理解,因为他们都有一些具有特定职责的方法,尤其是AsyncTask,有预处理的方法onPreExecute,有后台执行任务的方法doInBackground,有更新进度的方法publishProgress,有返回结果的方法onPostExecute等等,这就不像post这些方法,把所有的操作都一大坨的写在一个Runnable里。
    有了Android为我们提供了这些方法我们就可以很好的解决一些长时间处理的任务了,但是在使用的时候我们还必须注意以下几点:
    这些方法或者类必须在在UI线程中创建和调用
    其实这些方法和类最终的实现都是Android的Message、MessageQueue和Looper的机制,所以不要期待你会马上看到结果(效果),因为这是一个Loop一直循环出MessageQueue中的Message执行的过程,如果你没有看到效果,那么等等吧,因为还没有轮到你。
    有线程(多个)的地方就会有并发,会有资源共享冲突,所以在使用的时候谨慎点吧,说不准你的一个线程中使用的变量已经被另一个线程改的面目全非了

  3. Service与Activity怎么实现通信?答:

    Activity与Service进行通信的三种方式

    第一种 简单通信

    直接通过Intent进行传值,我们在启动一个Service的时候通过Intent的对象向Service进行传值,这种方式传递值比较不方便,性能不是很高。

    (1)在MainActivity中通过启动服务和终止服务的按钮分别调用startService(intent)和stopService(intent)来启动和停止服务

    (2)在Myservice中,我们通过onStartCommand(finalIntent intent,intflags,intstartId)这个函数来接收从Activity传过来的值

    第二种

    我们在绑定服务的时候,首先要做的就是让我们的MainActivity实现ServiceConnection类,实现这个类之后,我们还需要重写ServiceConnection类中的两个方法onServiceConnected和onServiceDisconnected,这两个方法分别是在绑定成功和服务所在进程崩溃的时候被调用,如果绑定成功了,那么onServiceConnected(ComponentName componentName, IBinder iBinder) 就会被执行,然后第二个参数IBinder正是MyService中onBind()方法的返回值,因此我们可以通过这个返回值来想MyService传递数据。

    (1)MyService 中我们创建一个Binder类,让其实现Android.os.Binder类,并且定义一个方法setData,然后我们通过onBind()方法将其对象返回MainActivity。(2)在MainActivity中,首先添加一个Binder对象,然后在ServiceConnection中获取MyService中返回的Binder对象,接着我们通过Binder对象调用它的方法setData向其传递数据

    第三种,监听服务中的进程的变化

    在MyService中

    (1)添加一个公开的接口Callback

    (2)在MyService内部添加一个变量(3)向外界派发信息(4)在Binder中返回一个当前的MyService对象,然外部可以添加事件的绑定在MainActivity中  。      我们可以通过onServiceConnected方法中的iBinder对象来实现MyService中Callback的接口,在Android中有一个安全机制,辅助线程是不能直接修改主线程中的数据的,因此我们需要再定义一个Hander对象。
  4. Handler通信具体到源码,是怎么实现的?答:Message这个类里有个 Handler target成员,表示这个消息由哪个Handler处理。Handler的sendMessage方法就是将这个成员变量设置为当前的Handler。不同类(非Activity)只要把Handler变量传进去就行。

  5. Handler的机制?答:andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。

    1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
    2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
    3) Message Queue(消息队列):用来存放线程放入的消息。

    4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。

    1.Handler创建消息

            每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示

    2.Handler发送消息

    UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。

    Handler、Looper、MessageQueue的初始化流程如图所示:

    Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。

    3.Handler处理消息

    UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。

    子线程通过Handler、Looper与UI主线程通信的流程如图所示。

  6. 怎么实现ListView多种布局?答:

    1)重写 getViewTypeCount() – 该方法返回多少个不同的布局
    2)重写 getItemViewType(int) – 根据position返回相应的Item
    getViewTypeCount()返回布局种类的数量
    getItemViewType(int position)返回当前Item布局类型,可以在这里实现我们的逻辑
    getView中我们根据当前Item布局类型,加载对应的布局。

  7. ListView与数据库绑定的实现?答:建立了一个Service类,来实现对数据库的各种操作,然后在这个类中添加对数据库操作的增删改查方法

  8. 怎么实现一个部分更新的 ListView?答:

    对listview的某一个item进行刷新

    1.要获取要刷新的item当前索引position和数据

    2.对获取的数据进行重置

    3.将重置的数据放到adapter中的数据集的原来的位置(根据position刷新原数据集的某一条数据)

    4.在listview中获取需要刷新的子item的view

    5.从更新过的数据集中获取新数据,更新viwe中的数据(handler中操作,实现界面的刷新)

    private void updateProgressPartly(int progress,int position){
    		int firstVisiblePosition = listview.getFirstVisiblePosition();
    		int lastVisiblePosition = listview.getLastVisiblePosition();
    		if(position>=firstVisiblePosition && position<=lastVisiblePosition){
    			View view = listview.getChildAt(position - firstVisiblePosition);
    			if(view.getTag() instanceof ViewHolder){
    				ViewHolder vh = (ViewHolder)view.getTag();
    				vh.pb.setProgress(progress);
    			}
    		}
    	}
  9. ListView卡顿的原因与性能优化,说的越多越好?答:

  10. 1..Adapter的getView方法里面convertView没有使用setTag和getTag方式;
    2.在getView方法里面ViewHolder初始化后的赋值或者是多个控件的显示状态和背景的显示没有优化好,抑或是里面含有复杂的计算和耗时操作;
    3.在getView方法里面 inflate的row 嵌套太深(布局过于复杂)或者是布局里面有大图片或者背景所致;
    4.Adapter多余或者不合理的notifySetDataChanged;
    5.listview 被多层嵌套,多次的onMessure导致卡顿,如果多层嵌套无法避免,建议把listview的高和宽设置为fill_parent. 如果是代码继承的listview,那么也请你别忘记为你的继承类添加上LayoutPrams,注意高和宽都是fill_parent的;
    ListView滚动速度优化主要可以应用以下几点方法来实现:

    1、使用Adapter提供的convertView

    convertView是Adapter提供的视图缓存机制,当第一次显示数据的时候,adapter会创建n个(n等于页面可见的item的数目)convertView,当下次需要显示新的item的时候,adapter会循环利用这些已经创建的convertView,减少再次创建convertView所带来的开销,从而达到性能的提升。

    2、使用自定义的视图缓存类

    就是自定义一个视图缓存类,在这个类中保存我们在item中使用到的视图的引用,通过convertView的setTag方法和getTag方法来存储这个视图缓存类引用和重新获取这个视图缓存类引用,其目的也是为了减少重复创建视图时的开销。

    3、减少不必要的视图更新

    ListView在滚动时会请求重新获取item,来显示不同内容的item,而如果在获取item时比较耗时就会造成在滚动时出现卡顿的现象。那我们可以通过监听ListView的滚动事件来使ListView处于不同的滚动状态时做不同的事情,比如在ListView处于滚动过程中加载少量的显示数据,当ListView处于空闲的状态时再加载所有的数据,这样就可以减少ListView在滚动过程中的开销,从而提高ListView的滚动速度。
  11. Android中的动画有哪些,区别是什么?答:两种,一种是Tween动画、还有一种是Frame动画。

    补间动画和帧动画。

    Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化。

    Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。

  12. JNI怎么使用?答:Java通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在Windows平台下是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使Java可以实现和本地机器的紧密联系,调用系统级的各接口方法

  13. 说说内存泄露的情况有哪些?答:

    1. 查询数据库而没有关闭Cursor
    2. 调用registerReceiver后未调用unregisterReceiver().
    3. 未关闭InputStream/OutputStream
    4.Bitmap使用后未调用recycle()
    5. Context泄露

  14. OOM是怎么引起的?怎么尽量避免 OOM 问题的出现?答:

    1 应用中需要加载大对象,例如Bitmap

    一张在pc机上用的1024*768图片,如果直接用在手机屏幕这种小屏幕上,不仅没有提高显示质量,还容易使内存吃紧。假设照片是用ARGB_8888格式,那么一张1024×768的图片需要占用3M的内存, 4-5张就OOM了。bitmap分辨率越高,所占用的内存就越大,这个是以2为指数级增长的。

    解决方案:当我们需要显示大的bitmap对象或者较多的bitmap的时候,就需要进行压缩来防止OOM问题。我们可以通过设置BitmapFactory.Optiions的inJustDecodeBounds属性为true,这样的话不会加载图片到内存中,但是会将图片的width和height属性读取出来,我们可以利用这个属性来对bitmap进行压缩。Options.inSampleSize 可以设置压缩比。

    ps: 在android 2.3和以前的版本,bitmap对象的像素数据都是分配在native heap中的,所以我们在调试过程中这部分内存是在java heap中看不到的,不过在android 3.0之后,bitmap对象就直接分配在java heap上了,这样便于调试和管理。因此在3.0之后我们可以复用bitmap的内存,而不必回收它,不过新的bitmap对象要大小和原来的一样,到了android 4.4之后,就只要高宽不超过原来的就行了

     此外,java heap 的大小是动态变化的,它像是一个容器,只有水快满了,在允许的范围内,它会扩充它的容量。当水常处于较少的情况下它会缩小其容量. 上面说过android 2.3之前bitmap对象都是在native heap中分配的,如果我们在生成一个bitmap对象之前,在java heap 分配了一块较大的内存,即使之后这段内存被回收了,但是我们的java heap大小不可能一下子就随着这块内存的回收而缩小,它需要一个过程。而我们又要在native上分配一个bitmap对象的内存,如果这时候 默认值-java heap(未缩小) = native heap的值不足以分配给这个bitmap对象,那么就会报OOM错误。
    

    2 持有无用的对象使其无法被gc,导致Memory Leak . 也就是我们说的内存泄漏。导致内存泄漏我了解的有以下几个方面。

    2.1 静态变量导致的Memory leak

    静态变量的生命周期和类是息息相关的,它们分配在方法区上,垃圾回收一般不会回收这一块的内存。所以我们在代码中用到静态对象,在不用的时候如果不赋null值,消除对象的引用的话,那么这些对象是很难被垃圾回收的,如果这些对象一多或者比较大的话,程序出现OOM的概率就比较大了。因为静态变量而出现内存泄漏是很常见的。

    2.2 不合理使用Context 导致的Memory leak

    android 中很多地方都要用到context,连基本的Activty 和 Service都是从Context派生出来的,我们利用Context主要用来加载资源或者初始化组件,在Activity中有些地方需要用到Context的时候,我们经常会把context给传递过去了,将context传递出去就有可能延长了context的生命周期,最终导致了内存泄漏。例如 我们将activty context对象传递给一个后台线程去执行某些操作,如果在这个过程中因为屏幕旋转而导致activity重建,那么原先的activity对象不会被回收,因为它还被后台线程引用着,如果这个activity消耗了比较多的内存,那么新建activity或者后续操作可能因为旧的activity没有被回收而导致内存泄漏。所以,遇到需要用到context的时候,我们要合理选择不同的context,对于android应用来说还有一个单例的Application Context对象,该对象生命周期和应用的生命周期是绑定的。选择context应该考虑到它的生命周期,如果使用该context的组件的生命周期超过该context对象,那么我们就要考虑是否可以用application context。如果真的需要用到该context对象,可以考虑用弱引用来WeakReference来避免内存泄漏。
    

    2.3 非静态内部类导致的Memory leak

    非静态的内部类会持有外部类的一个引用,所以和前面context说到的一样,如果该内部类生命周期超过外部类的生命周期,就可能引起内存泄露了,如AsyncTask和Handler。因为在Activity中我们可能会用到匿名内部类,所以要小心管理其生命周期。 如果明确生命周期较外部类长的话,那么应该使用静态内部类。

    2.4 Drawable对象的回调隐含的Memory leak

    当我们为某一个view设置背景的时候,view会在drawable对象上注册一个回调,所以drawable对象就拥有了该view的引用了,进而对整个context都有了间接的引用了,如果该drawable对象没有管理好,例如设置为静态,那么就会导致Memory leak.

    1)使用更加轻量的数据结构

    例如,我们可以考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构,下图演示了HashMap的简要工作原理,相比起Android系统专门为移动操作系统编写的ArrayMap容器,在大多数情况下,都显示效率低下,更占内存。通常的HashMap的实现方式更加消耗内存,因为它需要一个额外的实例对象来记录Mapping操作。另外,SparseArray更加高效在于他们避免了对key与value的autobox自动装箱,并且避免了装箱后的解箱。

    2)避免在Android里面使用Enum

    3)减小Bitmap对象的内存占用

    Bitmap是一个极容易消耗内存的大胖子,减小创建出来的Bitmap的内存占用是很重要的,通常来说有下面2个措施:

    inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。

    decode format:解码格式,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差异。

    4)使用更小的图片

    在设计给到资源图片的时候,我们需要特别留意这张图片是否存在可以压缩的空间,是否可以使用一张更小的图片。尽量使用更小的图片不仅仅可以减少内存的使用,还可以避免出现大量的InflationException。假设有一张很大的图片被XML文件直接引用,很有可能在初始化视图的时候就会因为内存不足而发生InflationException,这个问题的根本原因其实是发生了OOM。

    在Android上面最常用的一个缓存算法是LRU(Least Recently Use)

    5)复用系统自带的资源

    Android系统本身内置了很多的资源,例如字符串/颜色/图片/动画/样式以及简单布局等等,这些资源都可以在应用程序中直接引用。这样做不仅仅可以减少应用程序的自身负重,减小APK的大小,另外还可以一定程度上减少内存的开销,复用性更好。但是也有必要留意Android系统的版本差异性,对那些不同系统版本上表现存在很大差异,不符合需求的情况,还是需要应用程序自身内置进去。

    6)注意在ListView/GridView等出现大量重复子组件的视图里面对ConvertView的复用

    7)Bitmap对象的复用

    在ListView与GridView等显示大量图片的控件里面需要使用LRU的机制来缓存处理好的Bitmap。

    利用inBitmap的高级特性提高Android系统在Bitmap分配与释放执行效率上的提升(3.0以及4.4以后存在一些使用限制上的差异)。使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的bitmap会尝试去使用之前那张bitmap在heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小。

    8)避免在onDraw方法里面执行对象的创建

    类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。

    9)StringBuilder

    在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”。

    避免对象的内存泄露

    内存对象的泄漏,会导致一些不再使用的对象无法及时释放,这样一方面占用了宝贵的内存空间,很容易导致后续需要分配内存的时候,空闲空间不足而出现OOM。显然,这还使得每级Generation的内存区域可用空间变小,gc就会更容易被触发,容易出现内存抖动,从而引起性能问题。

    10)注意Activity的泄漏

    通常来说,Activity的泄漏是内存泄漏里面最严重的问题,它占用的内存多,影响面广,我们需要特别注意以下两种情况导致的Activity泄漏:

    内部类引用导致Activity的泄漏

    最典型的场景是Handler导致的Activity泄漏,如果Handler中有延迟的任务或者是等待执行的任务队列过长,都有可能因为Handler继续执行而导致Activity发生泄漏。此时的引用关系链是Looper -> MessageQueue -> Message -> Handler -> Activity。为了解决这个问题,可以在UI退出之前,执行remove Handler消息队列中的消息与runnable对象。或者是使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的。

    Activity Context被传递到其他实例中,这可能导致自身被引用而发生泄漏。

    内部类引起的泄漏不仅仅会发生在Activity上,其他任何内部类出现的地方,都需要特别留意!我们可以考虑尽量使用static类型的内部类,同时使用WeakReference的机制来避免因为互相引用而出现的泄露。

    11)考虑使用Application Context而不是Activity Context

    对于大部分非必须使用Activity Context的情况(Dialog的Context就必须是Activity Context),我们都可以考虑使用Application Context而不是Activity的Context,这样可以避免不经意的Activity泄露。

    12)注意临时Bitmap对象的及时回收

    虽然在大多数情况下,我们会对Bitmap增加缓存机制,但是在某些时候,部分Bitmap是需要及时回收的。例如临时创建的某个相对比较大的bitmap对象,在经过变换得到新的bitmap对象之后,应该尽快回收原始的bitmap,这样能够更快释放原始bitmap所占用的空间。

    需要特别留意的是Bitmap类里面提供的createBitmap()方法:

    这个函数返回的bitmap有可能和source bitmap是同一个,在回收的时候,需要特别检查source bitmap与return bitmap的引用是否相同,只有在不等的情况下,才能够执行source bitmap的recycle方法。

    13)注意WebView的泄漏

    Android中的WebView存在很大的兼容性问题,不仅仅是Android系统版本的不同对WebView产生很大的差异,另外不同的厂商出货的ROM里面WebView也存在着很大的差异。更严重的是标准的WebView存在内存泄露的问题,看这里WebView causes memory leak - leaks the parent Activity。所以通常根治这个问题的办法是为WebView开启另外一个进程,通过AIDL与主进程进行通信,WebView所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。

    14)资源文件需要选择合适的文件夹进行存放

    我们知道hdpi/xhdpi/xxhdpi等等不同dpi的文件夹下的图片在不同的设备上会经过scale的处理。例如我们只在hdpi的目录下放置了一张100100的图片,那么根据换算关系,xxhdpi的手机去引用那张图片就会被拉伸到200200。需要注意到在这种情况下,内存占用是会显著提高的。对于不希望被拉伸的图片,需要放到assets或者nodpi的目录下。

    15)谨慎使用static对象

    因为static的生命周期过长,和应用的进程保持一致,使用不当很可能导致对象泄漏,在Android中应该谨慎使用static对象。

    16)特别留意单例对象中不合理的持有

    虽然单例模式简单实用,提供了很多便利性,但是因为单例的生命周期和应用保持一致,使用不合理很容易出现持有对象的泄漏。

    17)珍惜Services资源

    18)优化布局层次,减少内存消耗

    越扁平化的视图布局,占用的内存就越少,效率越高。我们需要尽量保证布局足够扁平化,当使用系统提供的View无法实现足够扁平的时候考虑使用自定义View来达到目的。

    19)谨慎使用“抽象”编程

    很多时候,开发者会使用抽象类作为”好的编程实践”,因为抽象能够提升代码的灵活性与可维护性。然而,抽象会导致一个显著的额外内存开销:他们需要同等量的代码用于可执行,那些代码会被mapping到内存中,因此如果你的抽象没有显著的提升效率,应该尽量避免他们。

    20)谨慎使用多进程

    使用多进程可以把应用中的部分组件运行在单独的进程当中,这样可以扩大应用的内存占用范围,但是这个技术必须谨慎使用,绝大多数应用都不应该贸然使用多进程,一方面是因为使用多进程会使得代码逻辑更加复杂,另外如果使用不当,它可能反而会导致显著增加内存。当你的应用需要运行一个常驻后台的任务,而且这个任务并不轻量,可以考虑使用这个技术。

    一个典型的例子是创建一个可以长时间后台播放的Music Player。如果整个应用都运行在一个进程中,当后台播放的时候,前台的那些UI资源也没有办法得到释放。类似这样的应用可以切分成2个进程:一个用来操作UI,另外一个给后台的Service。

  15. 什么是 ANR 问题?为什么会引起 ANR 问题?答:ANR:Application Not Responding,五秒在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:
      对输入事件(如按键、触摸屏事件)的响应超过5秒
      意向接受器(intentReceiver)超过10秒钟仍未执行完毕
      Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast)。
      因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成 (或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 — 也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。

  16. Socker编程的步骤?答:> Android socket编程过程
      创建服务器的步骤:
    1,指定端口实例化一个ServerSocket
    2,调用ServerSocket的accept方法以在等待连接期间造成阻塞
    3,获取位于该底层Socket的流以进行读写操作
    4,将数据封装成流
    5,对Socket进行读写
    6,关闭打开的流
      创建客户端的步骤:
    1,通过IP地址和端口实例化Socket,请求连接服务器
    2,获取Socket上的流以进行读写
    3,把流包装进BufferedReader/PrintWriter的实例
    4,对Socket进行读写

    5,关闭打开的流

  17. 设计一个图片缓存加载机制?答;图片缓存:LRU机制 (LRU是Least Recently Used最近最少使用算法。内存管理的一种算法,对于在内存中但最近又不用的数据块(内存块)叫做LRU,Oracle会根据那些数据属于LRU而将其移出内存而腾出空间来加载另外的数据。)
    这是两种做法,还有一些应用在下载的时候使用了线程池和消息队列MQ,对于图片下载的效率要更好一些。


    图片缓存一般分为内存缓存和外存缓存。内存 缓存运用java的缓存机制,在程序完全退出后,缓存所在的内存空间可能被其它应用程序占用从而丢失。外存缓存一般放在程序特有的访问空间或者sd卡中, 在sd卡中存放的资源为公有资源,其它程序也可以访问,且对用户来讲没有一个强制清除缓存的规范机制。

    本文提供三种缓存策略:(1)LRU算法,固定缓存图片数量(max_num),当图片数量超出max_num时,将缓存中最近用的最少的图片删除。 (2)FTU算法,固定每张图片的缓存时限,以最后一次使用算起,超过时限后删除。(3)FMU算法,在存储器中固定一定大小的存储空间,超过固定空间后 将缓存中占用最大尺寸的图片删除。使用时只需要向方法体中传递图片的URL即可。

  18. Fragment嵌套多个Fragment会出现bug吗?答:

    Case 1:当使用Fragment去嵌套另外一些子Fragment的时候,我们需要去管理子Fragment,这时候需要调用ChildFragmentManager去管理这些子Fragment,由此可能产生的Exception主要是:
    java.lang.IllegalStateException: No activity

    首先我们来分析一下Exception出现的原因:
    通过DEBUG发现,当第一次从一个Activity启动Fragment,然后再去启动子Fragment的时候,存在指向Activity的变量,但当退出这些Fragment之后回到Activity,然后再进入Fragment的时候,这个变量变成null,这就很容易明了为什么抛出的异常是No activity

    这个Exception是由什么原因造成的呢?如果想知道造成异常的原因,那就必须去看Fragment的相关代码,发现Fragment在detached之后都会被reset掉,但是它并没有对ChildFragmentManager做reset,所以会造成ChildFragmentManager的状态错误。

    找到异常出现的原因后就可以很容易的去解决问题了,我们需要在Fragment被detached的时候去重置ChildFragmentManager,即:

    @Override
    	public void onDetach() {
    		super.onDetach();
    		try {
    			Field childFragmentManager = Fragment.class
    					.getDeclaredField("mChildFragmentManager");
    			childFragmentManager.setAccessible(true);
    			childFragmentManager.set(this, null);
    
    		} catch (NoSuchFieldException e) {
    			throw new RuntimeException(e);
    		} catch (IllegalAccessException e) {
    			throw new RuntimeException(e);
    		}
    	}

    Case 2:当我们从一个Activity启动了一个Fragment,然后在这个Fragment中又去实例化了一些子Fragment,在子Fragment中去有返回的启动了另外一个Activity,即通过startActivityForResult方式去启动,这时候造成的现象会是,子Fragment接收不到OnActivityResult,如果在子Fragment中是以getActivity.startActivityForResult方式启动,那么只有Activity会接收到OnActivityResult,如果是以getParentFragment.startActivityForResult方式启动,那么只有父Fragment能接收(此时Activity也能接收),但无论如何子Fragment接收不到OnActivityResult。

    这是一个非常奇怪的现象,按理说,应该是让子Fragment接收到OnActivityResult才对,究竟是什么造成的呢?这是由于某位写代码的员工抱怨没发奖金,稍稍偷懒了,少写了一部分代码,没有考虑到Fragment再去嵌套Fragment的情况。

    我们来看看FragmentActivity中的代码:

    protected void onActivityResult(int requestCode, int resultCode, Intent data)
      {
        this.mFragments.noteStateNotSaved();
        int index = requestCode >> 16;
        if (index != 0) {
          index--;
          if ((this.mFragments.mActive == null) || (index < 0) || (index >= this.mFragments.mActive.size())) {
            Log.w("FragmentActivity", "Activity result fragment index out of range: 0x" + Integer.toHexString(requestCode));
    
            return;
          }
          Fragment frag = (Fragment)this.mFragments.mActive.get(index);
          if (frag == null) {
            Log.w("FragmentActivity", "Activity result no fragment exists for index: 0x" + Integer.toHexString(requestCode));
          }
          else {
            frag.onActivityResult(requestCode & 0xFFFF, resultCode, data);
          }
          return;
        }
    
        super.onActivityResult(requestCode, resultCode, data);
      }

    很显然,设计者把Fragment的下标+1左移16位来标记这个request是不是Fragment的,拿到result再解码出下标,直接取对应的Fragment,这样并没有去考虑对Fragment嵌套Fragment做一个Map映射,所以出现了这种BUG。

    但是如果我们需要在OnActivityResult的时候处理一些事情的话,我们可以通过在子Fragment中以getParentFragment.startActivityForResult的方式来启动,然后在父Fragment中去接收数据,我们需要在子Fragment中提供一个方法,如:getResultData(Object obj),通过父Fragment中的子Fragment实例去调用这个方法,把相应的数据传过去,然后去更新子Fragment。

  19. Activity中如何动态的添加Fragment?答:

    MainActivity的布局:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <include layout="@layout/main_head" />
    
        <LinearLayout
            android:id="@+id/add_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"/>
    
    
    </LinearLayout>

    MainActivity主要代码:

    public class MainActivity extends ActionBarActivity implements OnClickListener {
        private ImageButton mTabWeixin;
        private ImageButton mTabFriend;
        private ImageButton mTabDiscover;
        private ImageButton mTabMe;
    
        private ContentFragment mWeiXinFragment;
        private FriendFragment mFriendFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
    
            initView();
        }
    
        public void initView() {
            // 初始化控件和声明事件
            mTabWeixin = (ImageButton) findViewById(R.id.weixin);
            mTabFriend = (ImageButton) findViewById(R.id.friend);
            mTabWeixin.setOnClickListener(this);
            mTabFriend.setOnClickListener(this);
    
            // 设置默认的Fragment
            setDefaultFragment();
        }
    
        @SuppressLint("NewApi")
        private void setDefaultFragment() {
            FragmentManager manager = getFragmentManager();
            FragmentTransaction transaction = manager.beginTransaction();
    
            mWeiXinFragment = new ContentFragment();
            transaction.replace(R.id.id_content, mWeiXinFragment);
            transaction.commit();
        }
    
        @SuppressLint("NewApi")
        @Override
        public void onClick(View v) {
            FragmentManager fm = getFragmentManager();
            // 开启Fragment事务
            FragmentTransaction transaction = fm.beginTransaction();
            switch (v.getId()) {
                case R.id.weixin:
                    if (mWeiXinFragment == null) {
                        mWeiXinFragment = new ContentFragment();
                    }
                    // 使用当前Fragment的布局替代id_content的控件
                    transaction.replace(R.id.id_content, mWeiXinFragment);
                    break;
                case R.id.friend:
                    if (mFriendFragment == null) {
                        mFriendFragment = new FriendFragment();
                    }
                    transaction.replace(R.id.id_content, mFriendFragment);
                    break;
            }
            // transaction.addToBackStack();
            // 事务提交
            transaction.commit();
        }
    }

    API:

    5、Fragment常用的API:

    Fragment常用的三个类:

    Android.app.Fragment 主要用于定义Fragment

    android.app.FragmentManager 主要用于在Activity中操作Fragment

    android.app.FragmentTransaction 保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白~

    a、获取FragmentManage的方式:

    getFragmentManager() // v4中,getSupportFragmentManager

    b、主要的操作都是FragmentTransaction的方法

    FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务

    transaction.add() 

    往Activity中添加一个Fragment

    transaction.remove()

    从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。

    transaction.replace()

    使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~

    transaction.hide()

    隐藏当前的Fragment,仅仅是设为不可见,并不会销毁

    transaction.show()

    显示之前隐藏的Fragment

    detach()

    将此Fragment从Activity中分离,会销毁其布局,但不会销毁该实例

    attach()

    将从Activity中分离的Fragment,重新关联到该Activity,重新创建其视图层次

    transatcion.commit()//提交一个事务

    注意:常用Fragment的哥们,可能会经常遇到这样Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。

    上述,基本是操作Fragment的所有的方式了,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。

    值得注意的是:如果你喜欢使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。

    a、比如:我在FragmentA中的EditText填了一些数据,当切换到FragmentB时,如果希望会到A还能看到数据,则适合你的就是hide和show;也就是说,希望保留用户操作的面板,你可以使用hide和show,当然了不要使劲在那new实例,进行下非null判断。

    b、再比如:我不希望保留用户操作,你可以使用remove(),然后add();或者使用replace()这个和remove,add是相同的效果。

    c、remove和detach有一点细微的区别,在不考虑回退栈的情况下,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。那么二者怎么取舍使用呢?如果你的当前Activity一直存在,那么在不希望保留用户操作的时候,你可以优先使用detach。

  20. 内存不足时,怎么保持Activity的一些状态,在哪个方法里面做具体操作?答;

    一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会得到保留. 

    但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有该activity的实例对象了. 如果之后这个activity重新回到前台, 之前所作的改变就会消失. 为了避免此种情况的发生, 开发者可以覆写onSaveInstanceState()方法. onSaveInstanceState()方法接受一个Bundle类型的参数, 开发者可以将状态数据存储到这个Bundle对象中, 这样即使activity被系统摧毁, 当用户重新启动这个activity而调用它的onCreate()方法时, 上述的Bundle对象会作为实参传递给onCreate()方法, 开发者可以从Bundle对象中取出保存的数据, 然后利用这些数据将activity恢复到被摧毁之前的状态.

  21. Scrollview怎么判断是否滑倒底部?答:


    getMeasuredHeight()是实际View的大小,与屏幕无关,而getHeight的大小此时则是屏幕的大小。当超出屏幕后, getMeasuredHeight() 等于 getHeight()加上屏幕之外没有显示的大小

    滚动到顶部判断:
    getScrollY() == 0
    滚动到底部判断:
    View childView = getChildAt(0);

    childView.getMeasuredHeight() <= getScrollY() + getHeight();

    其中getChildAt表示得到ScrollView的child View
    childView.getMeasuredHeight()表示得到子View的高度,

     getScrollY()表示得到y轴的滚动距离,

    getHeight()为scrollView可见的高度即屏幕的高度
    getScrollY()达到最大时加上scrollView的高度就的就等于它内容的高度了.
    判断滑动位置的地方,可以有两种方式:

    1、实现OnTouchListener来监听是否滑动到最底部
     
    1. OnTouchListener onTouchListener=new OnTouchListener(){    
    2.             @Override    
    3.             public boolean onTouch(View v, MotionEvent event) {   
    4.                 switch (event.getAction()) {  
    5.                     case MotionEvent.ACTION_UP:  
    6.                         if (childView  != null && childView .getMeasuredHeight() <= getScrollY() + getHeight()) {  
    7.                         } else if (getScrollY() == 0) {  
    8.                         }  
    9.                     break;  
    10.                 }  
    11.                 return false;  
    12.             }  
    13.  }   


    2、重写ScrollView的onScrollChanged的方法,在onScrollChanged函数中判断

    1. public class myScrollView extends ScrollView  
    2. {  
    3.     public myScrollView(Context context)  
    4.     {  
    5.         super(context);  
    6.     }  
    7.     public myScrollView(Context context, AttributeSet attributeSet)  
    8.     {  
    9.         super(context,attributeSet);  
    10.     }  
    11.   
    12.     @Override  
    13.     protected void onScrollChanged(int l, int t, int oldl, int oldt)  
    14.     {  
    15.         View view = (View)getChildAt(getChildCount()-1);  
    16.         int d = view.getBottom();  
    17.         d -= (getHeight()+getScrollY());  
    18.         if(d==0)  
    19.         {  
    20.             //you are at the end of the list in scrollview   
    21.             //do what you wanna do here  
    22.         }  
    23.         else  
    24.             super.onScrollChanged(l,t,oldl,oldt);  
    25.     }  

  22. ViewPager 的怎么做性能优化?答:

    当ViewPager切换到当前的Fragment时,Fragment会加载布局并显示内容,如果用户这时快速切换ViewPager,即Fragment需要加载UI内容,而又频繁地切换Fragment,就容易产生卡顿现象(类似在ListView快速滑动的同时加载图片容易卡顿)。

    优化方案:

    1.Fragment轻量化

     

    如果ViewPager加载的Fragment都比较轻量,适当精简Fragment的布局,可提高Fragment加载的速度,从而减缓卡顿现象。

     

    2.防止Fragment被销毁


    ViewPager在切换的时候,如果频繁销毁和加载Fragment,就容易产生卡顿现象,阻止Fragment的销毁可有效减缓卡顿现象。


    (1)    在PagerAdapter里覆盖destroyItem方法可阻止销毁Fragment

     @Override       
    public void destroyItem(ViewGroup container, int position, Object object) {
        //super.destroyItem(container, position, object);
    }

    (2)    通过PagerAdapter的setOffscreenPageLimit()方法可以设置保留几个Fragment,适当增大参数可防止Fragment频繁地被销毁和创建。

    风险:在Fragment比较多的情况下,部分低端机型容易产生OOM问题。


    3.Fragment内容延迟加载


    (1) 描述

    在切换到当前Fragment的时候,并不立刻去加载Fragment的内容,而是先加载一个简单的空布局,然后启动一个延时任务,延时时长为T,当用户在该Fragment停留时间超过T时,继续执行加载任务;而当用户切换到其他Fragment,停留时间低于T,则取消该延时任务。

    (2) 具体操作

    首先,设置延迟任务

     private Runnable LOAD_DATA = new Runnable() {        
    @Override
    public void run() {
    //在这里数据内容加载到Fragment上
    }
    };
    启动任务

    @Override 

    public View onCreateView(LayoutInflater inflater, ViewGroupContainer, Bundle savedInstanceState) { 

        //初始化视图,这里最好先设置一个进度对话框,提示用户正在加载数据
        initView();
        //启动任务,这里设置500毫秒后开始加载数据    handler.postDelayed(LOAD_DATA,500)
        return view;
    }
    若用户切换到其他Fragment则取消任务

    //判断Fragment是否可视的重载方法
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
      super.setUserVisibleHint(isVisibleToUser);
        if(!isVisibleToUser)
         mHandler.removeCallbacks(LOAD_DATA);
    }
    (3) 注意

    使用setUserVisibleHint判断用户是否切换到其他Fragment,这样的做法有个缺陷,因为会在ViewPager开始滑动的时候取消延时任务,而在滑动偏移量不足的情况下,ViewPager会继续回滚到当前Fragment,导致当前Fragment的加载任务被取消而又不会重新启动加载任务。

      这里我使用的做法是,给ViewPager增加一个OnPageChangeListener,,该监听器的onPageSelected(position)能监听ViewPager当前切换到哪个Fragment,在这里将其他Fragment的延迟加载任务取消掉。

  23. Asynctask具体用法?答:AsyncTask的使用方法:
    1. 

        AsyncTask对线程间的通讯做了包装,使后台线程和UI线程可以简易通讯:后台线程执行异步任务,将result告知UI线程。
    2.      使用方法:定义一个继承自AsyncTask的方法,把比较耗时的操作放在doInBackground中完成,onPostExecute方法中可以完成对UI的更新。
    下面对AsyncTask使用的参数及需要实现的方法做下详细的说明。
    AsyncTask
            Params:输入参数。对应的是调用自定义的AsyncTask的类中excute()方法中传递的参数。如果不需要传递参数,则直接设为Void即可。
    Progress:子线程执行的百分比。用于更新进度条。
    Result:返回值类型。和doInBackground()方法的返回值类型保持一致。
        onPreExecute():
    A.      无返回值类型,不传参数。
    B.      在执行实际的后台操作前,被UI 线程调用,无需我们手动调用。
    C.      作用:可以在该方法中做一些准备工作,如一些控件的实例化等。
    D.      AsyncTask类中该方法是空方法,可以不用实现。
    E.      需要强调的是,该方法在UI线程中被调用。
      doInBackground(Params... params):
    A.      返回值类型和Result保持一致。参数:若无,就传递Void;若有,就用Params
    B.      在执行实际的后台操作,被后台线程调用,无需我们手动调用。
    C.      作用:AsyncTask的主力军,所有耗时的操作在此方法中完成。
    D.      AsyncTask类中该方法是一个抽象方法,我们继承AsyncTask时必须覆写此方法。
    E.      需要强调的是,该方法在后台线程中被调用。
      publishProgress(Params... params):
    A.该方法无需覆写,直接调用即可。
    B.在执行此方法的时候会直接调用onProgressUpdate(Params... values)
    C.作用:用来调用onProgressUpdate方法,更新进度条。
    D.该方法一般在doInBackground方法中调用。
    onProgressUpdate(Params... values):
    A.      无返回值类型。参数:若无就传递Void;若有,就可用values
    B.      在publishProgress执行时被调用,无需我们手动调用。
    C.      作用:更新进度条
    onPostExecute(Result  result) :
    A.      无返回值类型。参数:和Result保持一致。
    B.      当后台操作结束时,此方法将会被调用,doInBackground的计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
    execute(Params... params):
    A.执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
    对于上面的说明,还需要注意的是:
    1.      AsyncTask,doInBackground(Params...params),execute(Params... params)这但三者的Params 类型必须是一致的。
    2.      doInBackground(Params...params)的返回值要作为onPostExecute(Result  result)的实参使用的,所以二者的类型也是必须一致的。
    另外,在使用的时候,有几点需要格外注意:
    1.异步任务的实例必须在UI线程中创建。
    2.execute(Params... params)方法必须在UI线程中调用。
    3.不要手动调用onPreExecute(),doInBackground(Params...params),onProgressUpdate(Progress... values),onPostExecute(Resultresult)这几个方法。
    4.不能在doInBackground(Params... params)中更改UI组件的信息。
    5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

  24. Asynctask的Do in background方法是怎么通知UI线程刷新进度条的?答:Asynctask的Do in background方法默认是返回 true ,表示任务完成

  25. Asynctask的Do in background方法默认是返回 true ,表示任务完成,如果想返回具体的数据呢,怎么做。如果Activity被销毁了,还会执行到postexcutd方法吗? 答:http://www.dewen.net.cn/q/3494

  26. View中onTouch,onTouchEvent,onClick的执行顺序?答:dispatchTouchEvent---->onTouch---->onTouchEvent----->onClick。

  27. 不使用动画,怎么实现一个动态的 View?答;如果想做2d动画 写一个类继承surfaceview 定时重画 写3d的话 继承glsurfaceview 然后在你的activity中的setcontentview设置你写的这个类即可 使用Timer定时器可以实现简单的View的动画,或者使用线程操作 自定义view,用线程重绘。

  28. Postvalidata与Validata有什么区别?答 :

    Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。 
    
    invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。 一个Android 程序默认情况下也只有一个进程,但一个进程下却可以有许多个线程。
    在这么多线程当中,把主要是负责控制UI界面的显示、更新和控件交互的线程称为UI线程,由于onCreate()方法是由UI线程执行的,所以也可以把UI线程理解为主线程。其余的线程可以理解为工作者线程。
    
    invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通知UI线程进行界面更新。
    
    而postInvalidate()在工作者线程中被调用

  29. Asset与raw都能存放资源,他们有什么区别?答

    *res/raw和assets的相同点:
    1.两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。

    *res/raw和assets的不同点:
    1.res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
    2.res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹

    *读取文件资源:
    1.读取res/raw下的文件资源,通过以下方式获取输入流来进行写操作
    ·        InputStream is =getResources().openRawResource(R.id.filename); 
    2.读取assets下的文件资源,通过以下方式获取输入流来进行写操作
    ·        AssetManager am = null; 
    ·        am = getAssets();
    ·        InputStream is = am.open("filename"); 

  30. 如何自定义ViewGroup?1、在新建一个PreviewLayout并继承自ViewGroup时会自己调价重新方法onLayout()这个方法是在你每次想ViewGroup添加View时调用,你可以在这儿设置每个view在Viewgroup中的位置。 2、光重写onLayout方法是不行的,还要重新onMeasure方法,并给每个View设置大小。

  31. 什么是 MVC 模式?MVC 模式的好处是什么?

  32. JVM 和Dalvik虚拟机的区别

  33. 应用常驻后台,避免被第三方杀掉的方法,讲讲你用过的奇淫巧技?

  34. 数据持久化的四种方式有哪些?答:在Android中,实现数据持久化主要有四种方式:Preferences,文件I/O,SQLite数据库,ContentProvider组件。

1、Android中有哪几种解析xml的方式,原理,区别 

链接:http://blog.csdn.NET/skibug/article/details/47778255

链接:http://blog.sina.com.cn/s/blog_5a48dd2d0100sdo9.html

2、android中解析json方法,原理,区别

链接:http://www.2cto.com/kf/201401/270452.html

链接:http://my.oschina.Net/sammy1990/blog/272510?p=1

3、为什么现在以json数据格式居多 

链接:http://www.cnblogs.com/SkySoot/archive/2012/04/17/2453010.html

4、数据存储方式

5、四种启动模式

《第一行代码》 P71

6、activity,fragment生命周期

链接:http://www.cnblogs.com/purediy/p/3276545.html

7、广播机制,注册方式有哪些 什么区别,顺序广播和无序广播

《第一行代码》 P198

8、Message+Handler+Looper

9、MVC,MVP android中的应用与区别

链接:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0313/2599.html

链接:http://blog.csdn.net/xijiaohuangcao/article/details/7925641

10、什么是ANR 什么情况下会出现ANR,如何避免

11、什么情况下会导致Force Close,如何避免

抛出运行时异常时就会导致Force Close,比如空指针、数组越界、类型转换异常等等。
捕获:可以通过logcat查看抛出异常的代码出现的位置,然后到程序对应代码中进行修改。
避免:编写程序时,要思维缜密,在可能出现异常的地方都作相应的处理,增强程序的健壮性。
链接:http://www.cnblogs.com/tianjian/archive/2011/10/27/2226633.html

12、描述android系统架构

链接:http://www.cnblogs.com/sandyclaire1990/p/4583485.html

13、android中webview

《Android程序员面试宝典》 P138

14、AIDL是什么,如何工作

《Android程序员面试宝典》 P70

15、dvm虚拟机

16、IPC进程间通信

链接:http://my.oschina.net/keeponmoving/blog/64218

17、NDK开发

《Android程序员面试宝典》 P276

18、内存泄露与优化 

19、电量优化

链接:http://blog.csdn.net/zhiying201039/article/details/8583526

链接:http://www.cnblogs.com/hanyonglu/p/4244035.html

20、AsyncTask相对于Java自带的线程池的好处

待解答  

21、android 事件分发机制

链接:http://www.cnblogs.com/duoduohuakai/p/3996385.html

上:http://blog.csdn.net/guolin_blog/article/details/9097463

下:http://blog.csdn.net/guolin_blog/article/details/9153747

22、什么是OOM,如何避免

23、android中如何传递数据,有哪几种方式

链接:http://blog.sina.com.cn/s/blog_70e5bf6e0101aga5.html

链接:http://www.2cto.com/kf/201311/256174.html

24、注册广播有哪几种方式,有什么区别

25、绘制 Activity 的生命流程图

26、注册Service需要注意什么

待解答

链接:http://zhidao.baidu.com/link?url=yCR79vJj04Ow6eASn4tfrhWbix5osTR5wTFw_jrL7o3FSOwdZp_zK9psp2pqfRHdDG92J7CXe5laV7Hrwog0BmFWLE-7S8ygD0RbZGMQs5G

链接:http://blog.csdn.net/pi9nc/article/details/18764415

27、Service与Activity怎么实现通信

《第一行代码》 P375

28、Handle通信具体到源码,是怎么实现的

链接:http://www.th7.cn/Program/Android/201504/439727.shtml

29、Handle的机制

链接:http://blog.csdn.net/fener10289/article/details/7569149

30、怎么实现ListView多种布局?

两种布局:http://my.oschina.net/erehmii/blog/103004

初步:https://www.zybuluo.com/linux1s1s/note/123965

进阶一:https://www.zybuluo.com/linux1s1s/note/134938

进阶二:http://www.bubuko.com/infodetail-982617.html

多布局适配器:http://mobile.51cto.com/aprogram-374701.htm

31、ListView与数据库绑定的实现

SQLite数据库:http://blog.csdn.net/richnaly/article/details/7790246

XML网络数据:http://my.oschina.net/bv10000/blog/108549

JSON数据:http://blog.sina.com.cn/s/blog_6f72ff900102vb1n.html

32、怎么实现一个部分更新的 ListView?

链接:http://blog.csdn.net/jdsjlzx/article/details/45582719

链接:http://www.cnblogs.com/android-HTML5/archive/2011/07/22/2534129.html

链接:http://www.pocketdigi.com/20100827/75.html

33、ListView卡顿的原因与性能优化,说的越多越好

链接:http://blog.csdn.net/androidzhaoxiaogang/article/details/8797539

链接:http://blog.csdn.net/linxcool/article/details/9793355

34、Android中的动画有哪些,区别是什么

《Android程序员面试宝典》 P220

链接:http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html

35、JNI怎么使用

链接:http://blog.csdn.net/xnwyd/article/details/7086384

链接:http://www.open-open.com/lib/view/open1324909652374.html

36、说说内存泄露的情况有哪些

链接:http://zhidao.baidu.com/link?url=mYuu6qGfMzOAkBKWX9gY4q7E3c6l_Cj4NbkwFedchumvozT0_srYnJZ_wTcbL4ouZStlkJGCBAw1rT6_CX1BM6H2oORkDgZx1VwTNQgE2Jq

链接:http://mobile.51cto.com/abased-406286.htm

37、OOM是怎么引起的?怎么尽量避免 OOM 问题的出现

链接:http://my.oschina.net/line926/blog/271175

链接:http://www.kankanews.com/ICkengine/archives/79916.shtml

链接:http://www.xuebuyuan.com/539037.html

38、什么是 ANR 问题?为什么会引起 ANR 问题?

链接:http://blog.sina.com.cn/s/blog_618199e60101kvbl.html

39、Socker编程的步骤

《Android程序员面试宝典》 P116

40、设计一个图片缓存加载机制

待解答

41、Fragment嵌套多个Fragment会出现bug吗

链接:http://blog.csdn.net/mobilexu/article/details/11711865

42、Activity中如何动态的添加Fragment

链接:http://www.desteps.com/mobile/android/0101057.html

链接:http://blog.csdn.net/manoel/article/details/7577349

43、内存不足时,怎么保持Activity的一些状态,在哪个方法里面做具体操作?

链接:http://blog.csdn.net/cyp331203/article/details/44985087

44、Scrollview怎么判断是否滑到底部

链接:http://www.07net01.com/2015/07/883727.html

45、ViewPager 的怎么做性能优化

链接:http://www.360doc.com/content/14/0523/10/11800748_380150418.shtml?

关于fragment+viewpager的优化:http://blog.csdn.net/u013173289/article/details/44002371

Android性能优化典范:http://hukai.me/android-performance-patterns/

46、Asynctask具体用法?

47、Asynctask的Do in background方法是怎么通知UI线程刷新进度条的?

48、Asynctask的Do in background方法默认是返回 true ,表示任务完成,如果想返回具体的数据呢,怎么做?

    如果Activity被销毁了,还会执行到postexcutd方法吗?

《第一行代码》 P364

链接:http://www.cnblogs.com/sandyclaire1990/p/4766680.html

待解答

49、View中onTouch,onTouchEvent,onClick的执行顺序

待解答

50、不使用动画,怎么实现一个动态的 View?

待解答      

自定义view,用线程重绘

51、android中Invalidate和postInvalidate的更新view区别?

链接:http://www.jb51.net/article/33100.htm

52、Asset与raw都能存放资源,他们有什么区别?

链接:http://blog.csdn.net/abc5382334/article/details/16813487

53、如何自定义ViewGroup?

链接:http://gqdy365.iteye.com/blog/1118853

链接:http://blog.csdn.net/manoel/article/details/39062737

54、什么是 MVC 模式?MVC 模式的好处是什么?

《Android程序员面试宝典》 P5

55、JVM 和Dalvik虚拟机的区别

链接:http://blog.csdn.net/x356982611/article/details/21983267

56、应用常驻后台,避免被第三方杀掉的方法,讲讲你用过的方法(至少4种)?

链接:http://www.zhihu.com/question/29826231

57、数据持久化的四种方式有哪些?

链接:http://www.kwstu.com/ArticleView/346933996_201383152258242


数据结构算法部分:

  1. 给最外层的rootview,把这个根视图下的全部button背景设置成红色,手写代码,不许用递归

  2. 给一串字符串比如abbbcccd,输出a1b3c3d1,手写代码(注意有个别字符可能会出现十次以上的情况)

  3. 一个序列,它的形式是12349678,9是最高峰,经历了一个上升又下降的过程,找出里面的最大值的位置,要求效率尽可能高

  4. 二叉查找树的删除操作,手写代码

  5. 反转链表,手写代码

  6. 二分查找,手写代码

  7. 有海量条 url,其中不重复的有300万条,现在希望挑选出重复出现次数最高的 url,要求效率尽可能的高

  8. 一篇英语文章,去掉字符只留下k个,如何去掉才能使这k个字符字典序最小

  9. 弗洛伊德算法和 Dijkstra算法的区别?复杂度是多少?讲讲 Dijkstra算法的具体过程

  10. 反转字符串,要求手写代码,优化速度、优化空间

  11. 给出两个无向图,找出这2个无向图中相同的环路。手写代码

  12. 单例模式,手写代码

  13. 生产者与消费者,手写代码

  14. 二叉树镜像,手写代码

  15. 最长不重复子串(最长重复子串),手写代码


操作系统部分:

  1. 分别从操作系统的内存角度与进程线程角度解释分析堆,栈二者的区别

  2. 什么是事务?

  3. OSI七层模型有哪些,各层次的作用

  4. TCP的三次握手过程,四次挥手过程,为什么需要三次?

  5. 说说操作系统中进程的通信方式?答:进程间的四种通讯方式:
    1>管道,FIFO
     

      管道(Pipe)是一种具有两个端点的通信通道:有一端句柄的进程可以和有另一

    端句柄的进程通信。管道可以是单向-一端是只读的,另一端点是只写的;也可以

    是双向的一管道的两端点既可读也可写。
      匿名管道(Anonymous Pipe)是 在父进程和子进程之间,或同一父进程的两个子

    进程之间传输数据的无名字的单向管道。通常由父进程创建管道,然后由要通信的

    子进程继承通道的读端点句柄或写 端点句柄,然后实现通信。父进程还可以建立两

    个或更多个继承匿名管道读和写句柄的子进程。这些子进程可以使用管道直接通信

    ,不需要通过父进程。
      匿名管道是单机上实现子进程标准I/O重定向的有效方法,它不能在网上使用,

    也不能用于两个不相关的进程之间
     
       命名管道(Named Pipe)是服务器进程和一个或多个客户进程之间通信的单向或

    双向管道。不同于匿名管道的是命名管道可以在不相关的进程之间和不同计算机之

    间使用,服务器建立命名管道时给它指定一个名字,任何进程都可以通过该名字打

    开管道的另一端,根据给定的权限和服务器进程通信。
      命名管道提供了相对简单的编程接口,使通过网络传输数据并不比同一计算机

    上两进程之间通信更困难,不过如果要同时和多个进程通信它就力不从心了。
     
       管道 和 FIFO是一样的,只是匿名管道需要在 父子进程间使用,FIFO是增强

    型的管道,适合传递较小的消息,FIFO实际相当于内核内部实现的一个共享文件。
    2>信号
     
      信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进

    程间通信外,进程还可以发送信号给进程本身。除了系统内核和root之外,只有具

    备相同uid、gid的进程才可以使用信号进行通信。
     
      /etc/passwd:uid与账号对应
     
      /etc/group:gid与群组对应
    3> 消息队列
     
      消息队列是消息的链接表,包括Posix消息队列systemV消息队列。有足够权限

    的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消

    息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限

    等缺。

    4> 共享内存
     
      使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通

    信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到

    进程间的同步及互斥。

    传递文件最好是用共享内存的方式,MAP_SHARED可以提供多进程共享一个文件的能

    力。
    管道 和 FIFO 是一样的,只是匿名管道需要在 父子进程间使用,FIFO是增强型的

    管道,适合传递较小的消息,FIFO实际相当于内核内部实现的一个共享文件。
    信号,严重的不建议使用,尤其是你的线程库不能做到异步安全的时候,使用信号

    作为通信方式很容易导致系统死锁。
    消息队列 与 FIFO 相似,是在FIFO的基础上封装的一个消息结构队列。

    建议使用 FIFO 或消息队列传递控制类型的消息(数据量小,有明确的数据结构)
    使用共享内存传递数据类型的消息(数据量大,数据结构多变)

  6. 浏览器输入地址之后,之后的过程?答:

    1.查找域名对应的IP地址。这一步会依次查找浏览器缓存,系统缓存,路由器缓存,ISPNDS缓存,根域名服务器。

    2.向IP对应的服务器发送请求。

    3.服务器响应请求,发回网页内容。

    4.浏览器解析网页内容。

    由于网页可能有重定向,或者嵌入了图片,AJAX,其它子网页等等,这4个步骤可能反复进行多次才能将最终页面展示给用户。

  7. 谈谈 HTTP 中Get 和 Post 方法的区别?答:Http方法:Get请求与Post请求的区别
    Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求
    Get是获取信息,而不是修改信息,类似数据库查询功能一样,数据不会被修改
    Get请求的参数会跟在url后进行传递,请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,%XX中的XX为该符号以16进制表示的ASCII,如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
    Get传输的数据有大小限制,因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了,不同的浏览器对URL的长度的限制是不同的。
    GET请求的数据会被浏览器缓存起来,用户名和密码将明文出现在URL上,其他人可以查到历史浏览记录,数据不太安全。在服务器端,用Request.QueryString来获取Get方式提交来的数据
    Post请求则作为http消息的实际内容发送给web服务器,数据放置在HTML Header内提交,Post没有限制提交的数据。Post比Get安全,当数据是中文或者不敏感的数据,则用get,因为使用get,参数会显示在地址,对于敏感数据和不是中文字符的数据,则用post
    POST表示可能修改变服务器上的资源的请求,在服务器端,用Post方式提交的数据只能用Request.Form来获取

  • Android面试常见问题列表。

    Java基础

    简述题(一)

    • &和&&的区别。
    • Get和Post的区别
    • http response code
    • udp连接和TCP的不同之处
    • java中的soft reference是个什么东西
    • 抽象类和接口的区别
    • 谈一下对java中的abstract的理解
    • Overload和Override的区别
    • Static Nested Class 和 Inner Class的不同
    • 内部类机制

    简述题(二)

    • 怎么用接口来连接两个层的
    • 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concreteclass)?
    • private和default有什么区别
    • java里的常量是怎么定义的
    • 类前边加+final的用处?
    • finally final finalize的作用?
    • java中final定义的类有什么特点
    • try{ return} catch{} finally{}; return还是finally先执行。
    • 数组有没有length()这个方法? String有没有length()这个方法?
    • 是否可以继承String类?
    • swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
    • 常量final string str=“ab”可不可以变成”abd”,为什么?
    • StringBuffer的作用?
    • String s=new String(“abc”); new了几个对象

    简述题(三)

    • 启动一个线程是用run()还是start()?
    • 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
    • 同步和异步的区别?
    • sleep和wait有什么区别? 一个是用来让线程休息,一个是用来挂起线程
    • abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
    • 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

    简述题(四)


  • Error与Exception的区别
  • Java中的异常处理机制的简单原理和应用。
  • Java内存回收机制,GC 垃圾回收机制,垃圾回收的优点和原理。并考虑2种回收机制。
  • 对象Object读写的是哪两个流
  • 反射,求字段的值和方法名
  • Socket编程的步骤
  • 什么是Java序列化

简述题(五)

  • 常见集合及区别
  • ArrayList和Vector区别,HashMap和HashTable区别
  • ArrayList和LinkedList的区别
  • List, Set, Map是否继承自Collection接口?
  • hashCode方法的作用
  • Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
  • 当x.equals(y)等于true时,x.hashCode()与y.hashCode()可以不相等,这句话对不对?
  • JSON,fastjson和GSON的区别
  • XML,解析XML的几种方式的原理与特点:DOM、SAX、PULL
  • MD5加密原理,可否解密。
  • heap和stack有什么区别。
  • 用最有效率的方法算出2乘以8等於几? (2<< 3)

java集合类框架
Android面试——Java相关

Android基础

Activity

  • 生命周期及横竖屏切换时生命周期
  • 启动模式
  • 内存不足时,怎么保持Activity的一些状态,在哪个方法里面做具体操作?
  • 介绍Activity、Service、Broadcast、BroadcastReceiver、Intent、IntentFilter
  • 怎么在启动一个activity时就启动一个service
  • 同一个程序不同的Activity如何放在不同的任务栈中?
  • 如何将一个Activity设置成窗口的样式
  • 如何退出Activity?如何安全退出已调用多个Activity的Application?
  • Activity中如何动态的添加Fragment?
  • activity的启动过程 参考
  • 不用Service,B页面为音乐播放,从A跳到B,再返回,如何使音乐继续播放?
  • windows和activity之间关系?
  • 一个activity打开另外一个activity,再打开一个activity?回去的时候发生了什么操作?
  • onActivityResult(int requestCode, int resultCode, Intent data)方法的用法;

Fragment

  • 生命周期
  • Fragment嵌套多个Fragment会出现bug吗?

Broadcast Receiver

  • 注册广播有哪几种方式,有什么区别
  • Android引入广播机制的用意?
  • 无序广播、有序广播 -1000——1000
  • 同优先级,清单文件中上面先收到
  • Broadcast、Content Provider 和 AIDL的区别和联系

Android基础——广播接收者BroadcastReceiver

Service

  • 注册Service需要注意什么
  • 什么是Service以及描述下它的生命周期。
  • Service与Activity怎么实现通信
  • Service有哪些启动方法,有什么区别,怎样停用Service?
  • 什么是IntentService?有何优点?
  • Service和Activity在同一个线程吗 main 线程 UI线程
  • Service里面可以弹土司么
  • 如何启用Service,如何停用Service
  • 什么时候使用Service?
  • 说说Activity、Intent、Service是什么关系
  • AIDL,两个android应用间的互相调用方法?
  • AIDL的全称是什么?如何工作?能处理哪些类型的数据

Android基础——Service
Android基础——IntentService
Android开发指导——Service
Android开发指导——绑定Service
Android开发指导——进程间通信AIDL

ContentProvider

  • 自定义一个contentProvider。
  • 请介绍下ContentProvider是如何实现数据共享的
    创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。
  • contentProvider权限;

AsyncTask简介

  • Asynctask具体用法?
  • Asynctask的Do in background方法是怎么通知UI线程刷新进度条的?
  • Asynctask的Do in background方法默认是返回 true ,表示任务完成,如果想返回具体的数据呢,怎么做。如果Activity被销毁了,还会执行到postexcutd方法吗?

Android基础——AsyncTask

ListView

  • 手指快速拖动ListView时,如何处理惯性引起的加载问题;
  • 怎么实现ListView多种布局?
  • ListView与数据库绑定的实现
  • 怎么实现一个部分更新的 ListView?
  • ListView卡顿的原因与性能优化,大量数据时,说的越多越好

UI相关

  • 谈谈UI中,Padding和Margin有什么区别?
  • drawable-hdpi的dpi是什么意思?
  • 请介绍下Android中常用的五种布局
  • Android中px,sp,dip,dp的区别与联系
  • 怎么处理屏幕适配的

简述题(一)

  • android开发中怎么去调试debug
  • 请解释下Android程序运行时权限与文件系统的权限的区别
  • JVM 和Dalvik虚拟机的区别
  • android dvm的进程和Linux的进程应用程序是否为同一个概念
  • sim卡的ef文件有何作用。
  • 你如何评价Android系统?优缺点
  • 谈下android系统的架构
  • 根据自己的理解描述下android数字签名

简述题(二)

  • 如何加载音乐信息,如何改善其效率。
  • Android程序与java程序的区别?
  • 什么是 MVC 模式?MVC 模式的好处是什么?
  • 在Android中MVC的具体体现
  • 简述Android应用程序的组成

简述题(三)

  • 如何让程序自动启动
  • 如何让程序不被系统自动销毁
  • 常见异常,5种运行时异常
  • 运行时异常与一般异常有何异同?
  • 什么情况会导致Force Close?如何避免?是否捕获导致其的异常
  • 什么是 ANR 问题?为什么会引起 ANR 问题?
  • 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?请说明原由
  • ContentValues相关,key是不是任意类型,value是不是任意类型
  • URL和URI区别用法
  • 数据存储,数据持久化的方式有哪些
  • 进程优先级
  • intent-filter属性及其含义;
  • 如何打开res/raw 目录中的数据库文件?
    简述题(四)
  • NotifactionManager使用原理
  • Asset与raw都能存放资源,他们有什么区别?
  • postInvalidate与invalidate有什么区别?
  • notifyDataSetChanged 和notifyDataSetInvalidated的区别
  • Serializable和Parcelable的区别
  • 子线程中更新UI的方法
  • Scrollview怎么判断是否滑倒底部
  • ViewPager 怎么做性能优化
  • 布局如何动态加载
  • 外存储器文件遍历输出文件名
  • Intent启动Activity有几种方式,请分别简述
  • AndroidManifest.xml文件中主要包含哪些信息
  • 列举常用的Android开源项目及应用场景
  • 文件和数据库哪个效率高

简述题(五)

  • 常见设计模式,并手动简单实现观察者模式
  • Handler机制
  • 热修复
  • 简述静默安装的原理,如何在无需Root权限的情况下实现静默安装
  • 什么是65535问题,如何防止或解决65535问题
  • 简述实现Android APK插件化的简单方法
  • 如何实现资源文件的混淆
  • 如何在不引用第三方工具的情况下防止应用二次打包?并对应用进行简单加固
  • 简述控制反转(Inversion of Control)的应用场景
  • 怎么考虑数据传输的安全性
  • xmpp openfire 基于xmpp openfire smack开发之Android客户端开发
  • 应用常驻后台,避免被第三方杀掉的方法,讲讲你用过的奇淫巧技?
  • 简述实现Android APK插件化的简单方法

JS交互

Android动画

  • Android中有哪些类型的动画,用属性动画实现控件的缩放
  • 不使用动画,怎么实现一个动态的 View?
  • Android中的动画有哪些,区别是什么

自定义View

  • View,SurfaceView,GLSurfaceView有什么区别
  • View的绘制
  • 如何自定义ViewGroup?
  • View刷新机制
  • android UI中的View如何刷新
  • 事件传递及处理机制
  • View中onTouch,onTouchEvent,onClick的执行顺序

JNI

  • JNI怎么使用
  • 简单描述你是如何进行JNI开发的
  • 在哪些情况下java代码中需要调用C代码

性能优化

  • 图片缓存及优化,设计一个图片缓存加载机制
  • 内存优化,布局优化,代码优化
  • 内存溢出OOM是怎么引起的?怎么尽量避免OOM问题的出现?
  • Android中引起内存泄露的原因

Android面试——APP性能优化

数据库
  • 分页查询数据
  • 如何将SQLite数据库与apk文件一起发布?
  • 左连接与右连接的区别
  • 描述Sqlite数据库(类型、关系);
  • 你的项目中Sqlite数据库中存储的数据用SharePreference来处理也可以,为什么不用SharePreference呢;
网络编程
编程算法题
  • 冒泡排序
  • 求素数
  • 单例模式——写一个Singleton出来
  • 二叉树遍历
  • 最长不重复子串(最长重复子串)
  • 有一个一维整型数组int[]data保存的是一张宽为width,高为height的图片像素值信息。请写一个算法,将该图片所有的白色不透明(xffffffff)像素点的透明度调整为5%。
  • 写一个求递归程序 求54321
  • 请使用java或者C++实现反转单链表
  • 生产者、消费者
  • 死锁(同步嵌套同步且锁不同)
  • 写一个多线程实例代码;
  • 写一个方法,交换两个变量的值?
  • 给最外层的rootview,把这个根视图下的全部button背景设置成红色,手写代码,不许用递归
  • 给一串字符串比如abbbcccd,输出a1b3c3d1,手写代码(注意有个别字符可能会出现十次以上的情况)
  • 一个序列,它的形式是12349678,9是最高峰,经历了一个上升又下降的过程,找出里面的最大值的位置,要求效率尽可能高
  • 二叉查找树的删除操作,手写代码
  • 二分查找,手写代码
  • 有海量条 url,其中不重复的有300万条,现在希望挑选出重复出现次数最高的 url,要求效率尽可能的高
  • 一篇英语文章,去掉字符只留下k个,如何去掉才能使这k个字符字典序最小
  • 弗洛伊德算法和 Dijkstra算法的区别?复杂度是多少?讲讲 Dijkstra算法的具体过程
  • 反转字符串,要求手写代码,优化速度、优化空间
  • 给出两个无向图,找出这2个无向图中相同的环路。手写代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值