一些面试题

OOM
OOM就是内存溢出,即Out Of Memory  
是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出(创建或解析Bitmap,分配特大的数组等)


解决:
图片优化(压缩,三级缓存)
优化dalvik的堆内存处理效率(手动干涉)oncreat中VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 
手动指定Android堆大小oncreat中VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小heap内存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理 
手动指定回收内存,指定gc 
if(bitmap!=null && !bitmap.isRecycled())
        {
            bitmap.recycle();
            System.gc();
        }




内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
Android应用内存泄漏的的原因有以下几个:
1查询数据库后没有关闭游标cursor  
2 构造Adapter时,没有使用 convertView 重用 
3 Bitmap对象不在使用时调用recycle()释放内存 
4 对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放




ANR
1.在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)
2.BroadcastReceiver在10秒内没有执行完毕


1、运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。(可以采用重新开启子线程的方式,然后使用Handler+Message的方式做一些操作,比如更新主线程中的ui等)
 
2、应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为 BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个 Service。(此处需要注意的是可以在广播接受者中启动Service,但是却不可以在Service中启动broadcasereciver,关于原因后续会有介绍,此处不是本文重点)
 
3、避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广 播时需要向用户展示什么,你应该使用Notification Manager来实现。






ListView优化
1.复用View
2.使用viewholder   并且最好是静态内部类。静态内部类,不持有外部类的引用,避免内存泄露…
3.listview高度设置成match-parent   (当我们固定listview的高度时(fill_parent或直接固定高度),那么listview很容易就能计算出容器内可以显示多少行。但如果我们使用了“wrap_content”,只有在屏幕内控件完全加载后才知道到底能显示多少行数据时,ListView自身便会做一些尝试性计算)
4.涉及图片等的时候使用异步加载,异步加载的时候引入线程池和线程队列(如果每当一个请求到达就创建一个新线程,开销是相当大的)
5.listview分页加载(加载更多)
6.对图片进行内存优化(当程序加载图片的时候,图片的尺寸可能很大,但是在手机上显示的时候,实际在程序中显示的时候,imageview会将大图缩小显示,其实图片中很多细节不会显示出来。但是当我们使用BitmapFactory解析图片的时候,BitmapFactory会将完整的图片解析出来,按照图片的分辨率来创建内存,转换成Bitmap,会占用非常大的内存)
InputStream is = this.getResources().openRawResource(R.drawable.pic1);
  BitmapFactory.Options options=new BitmapFactory.Options();
  options.inJustDecodeBounds = false;
  options.inSampleSize = 10;   //width,hight设为原来的十分一
  Bitmap btp =BitmapFactory.decodeStream(is,null,options);


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




/**
   * 以最省内存的方式读取本地资源的图片
          * @param context
          * @param resId
          * @return
          */
     public static Bitmap readBitMap(Context context, int resId){  
      BitmapFactory.Options opt = new BitmapFactory.Options();  
      opt.inPreferredConfig = Bitmap.Config.RGB_565;   
      opt.inPurgeable = true;  
      opt.inInputShareable = true;  
//获取资源图片  
      InputStream is = context.getResources().openRawResource(resId);  
return BitmapFactory.decodeStream(is,null,opt);  
  }


7.图片异步加载引起的错位问题的解决


因为listview的复用,导致在快速移动的时候,大量调用getview方法,因为复用,导致每一个imageview都可以同时有多个不同网址的异步任务进行加载,这样导致了图片的多次错乱,需要给每一次加载view时的imageview设置tag,这个tag就是网址,在异步任务设置图片的时候,要检查一下,是否当前网址和imageview的tag一致,一致才设置图片。
因为采用了复用,当listview滚动的时候,实际上显示的是之前加载过的item,之前的item中imageview的内容,就可能是之前其他条目加载的图片信息,这个时候,操作先显示其他条目的图片,之后开启了网络加载后,才会刷新为自身正确的数据。解决方式:在每次getview的时候,都将imageview显示的内容设置为“加载中”图片。覆盖原有旧的数据。




8.图片的加载引入三级缓存机制
9.滑动不加载图片停下加载图片
list.setOnScrollListener
getView中判断是否加载图片,停止时加载,滑动事时改变判断条件
10.RecyclerView替代listview的原因
RecyclerView封装了viewholder的回收复用。
RecyclerView使用布局管理器管理子view的位置(目前尚只提供了LinearLayoutManager),也就是说你再不用拘泥于ListView的线性展示方式(即竖列的展示方式),如果之后提供其他custom LayoutManager的支持,你能够使用复杂的布局来展示一个动态组件。
自带了ItemAnimation,可以设置加载和移除时的动画,方便做出各种动态浏览的效果。


生命周期
生命周期
onCreate()->onRestoreInstanceState->onStart()->onResume()->onSaveInstanceState()->onPause()->onStop()->onDestroy()
onStop()->onRestart()->onStart()


onCreat()初始化Activity,填充用户界面,数据绑定到控件,启动Service和定时器
onDestroy()清除所有资源
onStop()用来暂停或停止动画、线程、传感器、GPS、定时器、Service或其它专门用来更新用户界面的进程
onStart()/onStop()注册和注销Broadcast Receiver


启动Activity,得到返回结果
startActivityForResult(intent);

onActivityResult(xx  ,xxx,xx)请求码,结果码,intent


注册广播


配置文件注册-常驻型广播,即便你应用程序结束,一旦有了对应的广播过来,其还是会被激活;
代码注册-当应用程序结束了,广播自然就没有了,比如你在activity中的onCreate或者onResume中注册广播接收器
   在onDestory中卸载广播接收器。这样你的广播接收器就一个非常驻型的了。这种也叫动态注册。


service与activity通信
binder方式-当Activity通过调用bindService(Intent service, ServiceConnection conn,int flags),我们可以得到一个Service的一个对象实例,然后我们就可以访问Service中的方法
通过broadcast(广播)的形式-当我们的进度发生变化的时候我们发送一条广播,然后在Activity的注册广播接收器




handle
1.       Message


消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。


2.       Message Queue


消息队列,用来存放通过Handler发布的消息,按照先进先出执行。


3.       Handler


Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。


4.       Looper


循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理


5.    线程


UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。


运行机理:


      每个线程都可以并仅可以拥有一个Looper实例,消息队列MessageQueue在Looper的构造函数中被创建并且作为成员变量被保存,也就是说MessageQueue相对于线程也是唯一的。Android应用在启动的时候会默认会为主线程创建一个Looper实例,并借助相关的Handler和Looper里面的MessageQueue完成对Activities、Services、Broadcase Receivers等的管理。而在子线程中,Looper需要通过显式调用Looper. Prepare()方法进行创建。Prepare方法通过ThreadLocal来保证Looper在线程内的唯一性,如果Looper在线程内已经被创建并且尝试再度创建"Only one Looper may be created per thread"异常将被抛出。
      Handler在创建的时候可以指定Looper,这样通过Handler的sendMessage()方法发送出去的消息就会添加到指定Looper里面的MessageQueue里面去。在不指定Looper的情况下,Handler绑定的是创建它的线程的Looper。如果这个线程的Looper不存在,程序将抛出"Can't create handler inside thread that has not called Looper.prepare()"。
      整个消息处理的大概流程是:1. 包装Message对象(指定Handler、回调函数和携带数据等);2. 通过Handler的sendMessage()等类似方法将Message发送出去;3. 在Handler的处理方法里面将Message添加到Handler绑定的Looper的MessageQueue;4. Looper的loop()方法通过循环不断从MessageQueue里面提取Message进行处理,并移除处理完毕的Message;5. 通过调用Message绑定的Handler对象的dispatchMessage()方法完成对消息的处理。
      在dispatchMessage()方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:1. Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;2. Handler里面mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;3. 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。





equels  == 
equels是用来比较两个字符串是否相同而已,无论字符串是否是同一个对象,都会返回true,只要是相同就OK了。而"=="则是既要看是否相同,还要看是否同一个对象才能返回true,否则返回false;


String StringBuffer  StringBuilder
String:字符串常量,字符串长度不可变
StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型,可以调用StringBuffer的toString()方法。
StringBuilder:字符串变量(非线程安全)。在内部,StringBuilder对象被当作是一个包含字符序列的变长数组。


抽象类和接口区别
1.语法层面上的区别


   1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;


   2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;


   3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;


   4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。
JAVA中堆和栈的区别
2.设计层面上的区别
 1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。
 2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。


JAVA多态实现原理
重载,继承,转换
强制的:一种隐 式做类型转换的方法。


重载的:将一个标志符用作多个意义。


参数的:为不同类型的参数提供相同的操作。


包含的:类包含关系的抽象操作。


HttpGet  HttpPost
GET方式提交的数据最多只能是1024字节,理论上POST没有限制,可传较大量的数据
GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中)
POST把提交的数据则放置在是HTTP包的包体中


部分更新的ListView
众所周知Listview和Gridview的刷新界面的方式是调用adapter.notifyDataSetChanged()进行界面刷新。
但是此方法有其弊端,他是将界面中的数据全部刷新一遍,不论数据有没有变化。如果listview加载了很多的数据(如:100条)
在进行刷新时就会造成很大的系统开销如何像qq空间个人动态那样点赞只刷新一条呢:
主要原理:
对listview的某一个item进行刷新
1.要获取要刷新的item当前索引position和数据
2.对获取的数据进行重置
3.将重置的数据放到adapter中的数据集的原来的位置(根据position刷新原数据集的某一条数据)
4.在listview中获取需要刷新的子item的view
5.从更新过的数据集中获取新数据,更新viwe中的数据(handler中操作,实现界面的


ListView卡顿优化
在构造方法中耗时会导致ListView第一次加载时比较慢, 但是如果在getView方法中耗时就会导致整个ListView卡顿
ViewHolder
耗时操作异步






事件执行顺序
dispatchTouchEvent---->onTouch---->onTouchEvent----->onClick


dispatchTouchEvent(MotionEvent ev)



onInterceptTouchEvent(MotionEvent ev) 



onTouchEvent(MotionEvent ev)


当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由  dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。


Assets和raw区别
同:两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制
异:
1.res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
2.res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹


动画
三种(补间动画,逐帧动画,属性动画 )
属性动画 能够让对象的属性动起来
补间动画
(res/anim)
alpha(淡入淡出)
scale(缩放)
translate(移动)
rotate(旋转)


MVC  MVP
MVC的View直接与Model打交道,Controller只转发请求(View的请求)和通知(Model处理完之后的通知),不传递数据(业务结果),而是由View直接向Model拿数据。
MVP的View不与Model直接联系,所有的请求、结果通知、数据传递都是通过Controller转发,View和Model彼此不知道对方的存在。在MVP框架里,用Presenter代替MVC的Controller,而且View不再与Model交互。


LruCache
    1、这其实就是一个LinkedHashMap,任意时刻,当一个值被访问时,它就会被移动到队列的开始位置,所以这也是为什么要用LinkedHashMap的原因,因为要频繁的做移动操作,为了提高性能,所以要用LinkedHashMap。当cache满了时,此时再向cache里面添加一个值,那么,在队列最后的值就会从队列里面移除,这个值就有可能被GC回收掉。


    2、如果我们想主动释放内存,也是可以的,我们可以重写entryRemoved(Boolean, K, V, V)方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值