Android工程师面试题大全

本文深入探讨了Java内存泄露的原因及解决方法,包括资源对象管理、Bitmap优化、使用ApplicationContext替代Context、避免注册未取消的组件等。同时,对比了ArrayList与LinkedList的区别,以及HashMap与Hashtable的异同。此外,阐述了Iterator与Enumeration的区别,接口使用注意事项,以及final方法的使用场景。最后,介绍了Handler机制对Activity生命周期的影响和Android启动模式的四种类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java基础: 
1、内存泄露的原因: 
资源对象没关闭。 

如Cursor、File等资源。


他们会在finalize中关闭,但这样效率太低。

容易造成内存泄露。

SQLiteCursor,当数据量大的时候容易泄露。
使用Adapter时,没有使用系统缓存的converView。

即时调用recycle()释放不再使用的Bitmap。 


适当降低Bitmap的采样率,如:

BitmapFactory.Options options = newBitmapFactory.Options();   
options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的四分之一   
Bitmap bitmap =BitmapFactory.decodeStream(cr.openInputStream(uri), null, options); preview.setImageBitmap(bitmap);


使用application的context来替代activity相关的context。 
尽量避免activity的context在自己的范围外被使用,这样会导致activity无法释放。
注册没取消造成内存泄露 
如:广播
集合中的对象没清理造成的内存泄露我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。

Handler应该申明为静态对象, 并在其内部类中保存一个对外部类的弱引用。如下:

static class MyHandler extends Handler
{
       WeakReference<Activity > mActivityReference;
       MyHandler(Activity activity)
      {
            mActivityReference= new WeakReference<Activity>(activity);
      }
     @Override
     public void handleMessage(Message msg)
    {
           final Activity activity = mActivityReference.get();
           if (activity != null)
          {
                 mImageView.setImageBitmap(mBitmap);
          }   
     }
}


2、ArrayList和LinkedList的区别 

  • ArrayList初试大小为10,大小不够会调用grow扩容:length = length + (length >> 1)
  • LinkedList中Node first,last。分别指向头尾
  • ArrayList和LinkedList在性能上各 有优缺点,都有各自所适用的地方,总的说来可以描述如下:

  1. 对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对 
    ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是 
     统一的,分配一个内部Entry对象。
  2. 在ArrayList的 中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
  3. LinkedList不 支持高效的随机元素访问。
  4. ArrayList的空 间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间 
     可以这样说:当操作是在一列 
    数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中 
     间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
3、hashmap和hashtable的不同 
  1. 继承不同。 

    复制代码
    1
    2
    public class Hashtable extends Dictionary implements Map
    public class HashMap extends AbstractMap implements Map
  2. Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
  3. Hashtable中,key和value都不允许出现null值。 
    在HashMap中,null可以作为键,这样的键只有一个;可以有 
    一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 
    HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 
     而应该用containsKey()方法来判断。
  4. 两个遍历方式的内部实现上不同。 
    Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
  5. 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。 
    6.Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
  6.  
  7. 4、Iterator和Enumeration的不同

  1. 函数接口不同 
    Enumeration只有2个函数接口。通过Enumeration,我们只能读取集合的数据,而不能对数据进行修改。       Iterator只有3个函数接口。Iterator除了能读取集合的数据之外,也能数据进行删除操作。
  2. Iterator支持fail-fast机制,而Enumeration不支持。       Enumeration 是JDK 
    1.0添加的接口。使用到它的函数包括Vector、Hashtable等类,这些类都是JDK 
    1.0中加入的,Enumeration存在的目的就是为它们提供遍历接口。Enumeration本身并没有支持同步,而在Vector、 
    Hashtable实现Enumeration时,添加了同步。而Iterator 是JDK 
    1.2才添加的接口,它也是为了HashMap、ArrayList等集合提供遍历接口。Iterator是支持fail-fast机制的:当多个线程对 
    同一个集合的内容进行操作时,就可能会产生fail-fast事件。

ail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内 
容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变 
了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

5、接口的注意点
  1. 接口中的字段全部默认为 public static类型。
  2. 接口中的方法全部默认为 public类型。
  3. 接口中可以申明内部类,而默认为public static,正因为是static,只是命名空间属于接口,代码逻辑不属于接口。所以不违法接口定义。
  4. 接口本身可以申明为public或者缺省。
  5. 抽象类继承自某接口。如果在抽象类中实现了父类(接口)中的方法,在其子类可以不用实现,否则在子类必须实现。


6、final方法 
将方法声明为final那有两个原因,第一就是说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且 
也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。第二就是允许编译器将所有对此方法的调用转化为 
inline调用的机制,它会使你在调用final方法时,直接将方法主体插入到调用处,而不是进行例行的方法调用,例如保存断点,压栈等,这样可能会使 
你的程序效率有所提高,然而当你的方法主体非常庞大时,或你在多处调用此方法,那么你的调用主体代码便会迅速膨胀,可能反而会影响效率,所以你要慎用 
final进行方法定义。



Android知识点 

1、Handler机制 
  1. Handler对Activity finish影响。 
    在开发的过程中碰到一个棘手的问题,调用Activity.finish函数 
    Acitivity没有执行生命周期的ondestory函数,后面查找半天是因为有一个handler成员,因为它有一个delay消息没有处理,调用 
    Activity.finish,Activity不会马上destory,所以记得在Ativity 
    finish前清理一下handle中的未处理的消息,这样Activity才会顺利的destory
  2. Looper 
    通过调用Looper.prepare()创建Looper()对象并绑定到ThreadLocal变量中。 
    Looper里面包含了messageQueue。 
    构造器如下: 

    复制代码
    1
    2
    3
    4
    5
    6
    private Looper()
    {
         mQueue = new MessageQueue();
         mRun = true;
         mThread = Thread.currentThread();
    }
  3. loop()函数 
    1)从Looper中取出MessageQueue; 
    2)循环从MessageQueue中取出Message; 
    3)从Message中取出Target(Handler对象); 
    4)调用tartget的dispatchMessage分发消息。
  4. Handler对象 
     重要成员变量: 

    复制代码
    1
    2
    3
    final MessageQueue mQueue;
    final Looper  mLooper;
    final Callback mCallback;   //用于回调

    Handler对象在发送消息的时候,将MSG的target变量设为自己。这样在Looper对象循环取出msg的时候就可以调用对应handler的dispatchMessage()。此函数分发消息的优先级如下: 
    Message在创建的时候调用Obtain设置了Callback。 
    Handler在创建的时候传入了Callback。 
    交给Handler子类的HandleMessage处理(通常的做法)。


2、Android启动模式 

standard和singleTop模式。 
这两种比较简单。创建Activity放入当前的任务栈中,若当前是singleInstace,则放入设置的任务栈中。其中如果Activity在栈顶,则调用onNewIntent。 
singletask:栈内复用模式。不是在当前任务栈中查找是否存在,实际过程如下:
  1. 查找该Activity所需的任务栈是否存在(由taskAffinity控制,或者默认为包名)。
  2. 在任务栈当中查找该Activity是否存在。 
    这里面存在任务栈的切换,也就是当开启的singtask类型的Activity不属于当前任务栈时,则会切换到其任务栈。
singleInstance:单实例模式。 
包含了singleTask的所有特性,另外加上:设置为该模式的Activity,只能单独存在于一个任务栈中。当有两个singleInstace的Activity设置成同样的任务栈时,会出现两个同名的任务栈,分别用来存放同名的Activity。 
注:在任何跳转的时候,首先调用本Activity的onPause,然后跳转。如果被跳转的activity由于启动方式而没创建新的实例,则会先调用onNewIntent,然后按照正常的生命周期调用。 
如 
1:A→B,A:onPause;B:onCreate,onStart,onResume。 
2:A(singleTop)→A,A:onPause;A:onSaveInstanceState;A:onResume。 

3、View的绘制 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值