Android 面试准备
系统框架.png
横竖屏切换时候Activity的生命周期
他切换时具体的生命周期是怎么样的:
1、新建一个Activity,并把各个生命周期打印出来
2、运行Activity,得到如下信息
onCreate-->
onStart-->
onResume-->
3、按crtl+f12切换成横屏时
onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
4、再按crtl+f12切换成竖屏时,发现打印了两次相同的log
onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
onSaveInstanceState-->
onPause-->
onStop-->
onDestroy-->
onCreate-->
onStart-->
onRestoreInstanceState-->
onResume-->
-
不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
-
设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
-
设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
-
当前Activity产生事件弹出Toast和AlertDialog的时候Activity的生命周期不会有改变
-
Activity运行时按下HOME键(跟被完全覆盖是一样的):onSaveInstanceState --> onPause --> onStop,再次进入激活状态时: onRestart -->onStart--->onResume
Android中IntentService的原理及使用:
http://laokaddk.blog.51cto.com/368606/1340540/
Android屏幕适配全攻略(最权威的官方适配指导):
http://www.cocoachina.com/android/20151030/13971.html
android的资源限定符的使用
(1) final:修饰符(关键字),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
(2) finally:在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally块(如果有的话)。
(3) finalize:方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
-
如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
-
如果两个对象不equals,他们的hashcode有可能相等。
-
如果两个对象hashcode相等,他们不一定equals。
-
如果两个对象hashcode不相等,他们一定不equals。
sleep()和wait()的区别###
sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;
sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象的机锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。
在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。
wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;
wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。
wiat()必须放在synchronized block中,否则会在program runtime时扔出”java.lang.IllegalMonitorStateException“异常。
所以sleep()和wait()方法的最大区别是:
- sleep()睡眠时,保持对象锁,仍然占有该锁;
- wait()睡眠时,释放对象锁。
- 但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException(但不建议使用该方法)。
Java GC机制主要完成3件事:
- 确定哪些内存需要回收
- 确定什么时候需要执行GC
- 如何执行GC
Java内存分配和回收的机制概括的说,就是:分代分配,分代回收。对象将根据存活的时间被分为:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区)
Java内存泄露与溢出的区别:
- 内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出
- 而Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源
如何避免内存溢出:
-
从代码层面进行优化完善,尽量避免该情况发生
-
调整优化服务器配置:
-
设置-Xms、-Xmx相等
-
设置NewSize、MaxNewSize相等
-
设置Heap size, PermGen space:
Tomcat 的配置示例:修改 %TOMCAT_HOME%/bin/catalina.bat or catalina.sh
在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m
-
如何避免内存泄露:
- 尽早释放无用对象的引用
- 程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer
- 尽量少用静态变量
- 避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作
- 尽量运用对象池技术以提高系统性能
- 不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象
- 优化配置
单例模式
public class Singleton{}
-
懒汉模式
private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { //懒汉模式(线程不安全) return instance == null ? new Singleton() : instance; }
-
线程安全懒汉模式
private static Singleton instance = null; private Singleton() { } public static synchronized Singleton getInstance() { //懒汉模式(加锁,线程安全) return instance == null ? new Singleton() : instance; }
-
饿汉模式
//饿汉模式 private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; }
-
变种饿汉模式
饿汉变种模式 private static Singleton instance = null; private Singleton() { } static { instance = new Singleton(); } public static Singleton getInstance(){ return instance; }
-
静态内部类
//静态内部类 private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return SingletonHolder.INSTANCE; }
-
双重校验锁
//双重校验锁 //volatile是一个类型[修饰符] //(type specifier)。 // 它是被设计用来修饰被不同线程访问和修改的变量。 // 如果不加入 volatile,基本上会导致这样的结果: // 要么无法编写多线程 程序,要么[编译器] 失去大量优化的机会 private volatile static Singleton instance; private Singleton() { } public static Singleton getSingleton() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }
观察者模式###
eg:
- OnCLickListener
- EventBus
冒泡排序
public void bubbleSort(int[] a) {
int temp = 0;
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
查找排序
public void selectorSort(int[] a) {
for (int i = 0; i < a.length; i++) {
int min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
}
}
if (i != min) {
int tmp = a[i];
a[i] = a[min];
a[min] = tmp;
}
}
}
快速排序
public void quickSort(int[] data, int start, int end) {
// 设置关键数据key为要排序数组的第一个元素,
// 即第一趟排序后,key右边的数全部比key大,key左边的数全部比key小
int key = data[start];
// 设置数组左边的索引,往右移动比key大的数
int i = start;
// 设置数组右边的索引,往左移动比key小的数
int j = end;
// 如果左边索引比右边索引小,则还有数据没有排序
while (i < j) {
while (data[j] >= key && j > i) {
j--;
}
data[i] = data[j];
while (data[i] < key && i < j) {
i++;
}
data[j] = data[i];
}
// 此时 i==j
data[i] = key;
// 递归调用
if (i - 1 > start) {
// 递归调用,把key前面的完成排序
quickSort(data, start, i - 1);
}
if (i + 1 < end) {
// 递归调用,把key后面的完成排序
quickSort(data, i + 1, end);
}
}
java中的四类常见引用类型
-
强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。 ps:强引用其实也就是我们平时A a = new A()这个意思。 -
软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 -
弱引用(WeakReference)
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。 -
虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
原文:java中四种引用类型
http://www.pocketcn.com/forum-viewthread-tid-1661-fromuid-1477.html
关于图片加载OOM问题的总结提供两篇好文:
http://stackoverflow.com/questions/10743381/when-should-i-recycle-a-bitmap-using-lrucache
http://blog.csdn.net/guolin_blog/article/details/9316683
总结一下解决加载图片出现OOM的问题主要有以下方法:
- 不要加载原始大图,根据显示控件进行比例缩放后加载其缩略图。
- 不要在主线程中加载图片,主要在listview和gridview中使用异步加载图片是要注意处理图片错位和无用线程的问题。
- 使用缓存,根据实际情况确定是否使用双缓存和缓存大小。
原文地址:http://www.codeceo.com/article/android-load-image-oom.html
Activity的启动模式,推荐:
http://blog.csdn.net/zhangjg_blog/article/details/10923643