- 1.怎么加速布局的绘制过程?
android3.0引入了硬件加速,他可以不用遍历整个ViewTree来进行重绘,只重绘改变了的组件。
传统的是通过draw()或者invalidate()方法通知屏幕刷新。
硬件加速的是将draw()方法里要绘制的图形放入DisplayList中,当这个ViewTree的DisplayList全部记录完成后,通过RootView中的DisplayList把改变的View,从新绘制。
分成四个级别:Appliction,Activity,Window,View
- 2.谈一谈对象的生命周期?
java对象在虚拟机上分7个阶段。
1.创建阶段(分配空间,初始化工作)
2.应用阶段(被引用持有)
3.不可见阶段(没有任何对象引用)
4.不可达阶段(对象不再被任何强引用持有)
5.收集阶段(GC已经打算回收它)
6.终结阶段(执行完finalize()方法)
7.对象空间重新分配阶段(GC回收该对象占用的空间)
- 3 . java内存回收机制?
最近分配的对象存放到年轻代,一段时间后,移动到年老代,最后还没有被GC回收的话,进入永久代。
年轻代:复制算法进行gc回收
年老代:标记算法进行gc回收
永久代:存放静态数据
- 4 . 常见的内存泄漏场景?
1)资源对象未关闭(File)
2)接口回调监听,在Activity类销毁时,没有取消注册
3)静态变量持有大量对象,没有释放。如将Bitmap放入静态列表中,使用完没有释放。
4)非静态内部类 初始化为静态对象,传入了Activity的上下文。(可以使用Appliction上下文,或者在使用完外部引用对象时,释放也可以)
5)Handler的使用。Handler通过发送Message与主线程进行交互,每一个Message发出后存储在MessageQueue中,通过Looper进行轮询处理消息。当Activity退出时,消息队列只能中还有未处理的Message,Message持有handler实例的引用,handler又持有Activity的引用。最后导致activity无法被释放。
解决办法:
方法1:静态Handler+持有对象使用弱引用。
方法2:Destory()时,移除消息队列中的消息。
- 5 . LruCache类的使用介绍?
最近最少使用缓存。内部维护一个LinkedHashMap双向链表,然后进行了线程安全的封装。当数据被访问时,它被放到队列的尾部,当缓存将满的时候,队列头部的值将被丢弃。android 官方推荐他作为图片的内存缓存工具。
- 6 .请介绍一下Set接口和Map接口的关系?
他们都是java提高的集合类,但是Set接口是继承Collection,Map没有继承。
Set类是不可以存放相同元素的集合。
Map类是存放键值对,key不可以相同。
- 7 . HashMap和HashSet的关联和区别?
HashSet实现了Set接口,它不允许集合中有重复对象,需要重新equals()和hashCode()方法,这样才能比较对象的值是否相等。线程不安全的。
HashMap实现了Map接口,存放键值对,底层哈希表实现。允许键值对存null。线程不安全的。
Map集合是Set集合的扩展。
关系:
Map集合的key具有一个特征,所有的key不能重复,key之间没有顺序,将所有的key集中起来,就组成了一个Set集合,所以map集合提供了(SetkeySet()) 方法返回所有key组成的Set集合。
- 8.Hash存储机制的快速存取原理?
哈希表也叫散列表,它是基于快速存取角度设计的,是“空间换时间的”做法。
- 9 . 线性表的理解?
它是从数据逻辑结构进行划分中的一种,集合,线性结构,树形结构,图形结构。
线性结构主要就是线性表,非线性结构指的是树和图。
线性表是一对一的关系。分为顺序实现和链式实现,链式又分为单链表,循环链表,双向链表。
List接口就是线性表,分为ArrayList和LinkedList现实。
- 10.顺序实现和链式实现的比较优缺点?
顺序表:空间性能上,因为存储空间是静态分布的,所有总有空间被浪费。时间性能上,逻辑顺序和物理存储顺序一致,查找和读取时高效。
链式表:空间性能上,存储空间是动态分布的,所以不会有空间浪费,但是增加了节点,又增加了额外的空间。时间性能上,插入和删除高效。
- 11.栈和队列的区别?
他们是特殊的线性表, 只提供了插入和删除两个功能。
栈:先进后出,栈顶插入和删除。(链式栈更高效比顺序栈)
队列:先进先出,队尾插入,队头删除。
- 12 . 排序
private static int[] nums = {21,30,48,32,16,9};
//直接选择排序 直接排序是进行n-1次处理 缺陷:每次只能确定一个最小的值
//时间复杂度为o(n2) 每次找到最小的
private static void fast() {
int i ;
int j ;
int temp;
try{
for (i=0; i < nums.length ; i++){
// j>i 完成排序的就不需要再排序
for (j=nums.length-1 ; j > i ; j-- ){
if(nums[i] > nums[j]){
temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
}
System.out.println( Arrays.toString(nums));
}
}catch (Exception ex){
ex.printStackTrace();
}
}
//冒泡排序 每次找到最大的
private static void bubbleSort(){
int temp,i,j;
for (i=0 ; i < nums.length-1 ; i++){
for (j = 0 ; j < nums.length-1-i ; j++){
if(nums[j] > nums[j+1]){
temp = nums[j+1];
nums[j+1] = nums[j];
nums[j] = temp;
System.out.println( Arrays.toString(nums));
}
}
}
}
- 13 .MeasureSpec类的介绍?
MeasureSpec是在onMeasure函数中测试大小的的类。它是一个32位的int值,高2位是测量模式,低32位是测量大小。
分为3种模式:
1.exactly :精确模式,100dp或者match_parent
2.at_most:最大模式,wrap_content。
3.unspecified:想多大就多大。
- 14 .自定义View时为什么要重写onMeasure方法?
view类默认的onMeasure()方法只处理exactly这一种模式,所以在自定义控件时,如果不重写onMeasure()方法的话,就只有exactly这一种模式。
如果需要自定义组件支持wrap_content属性,那么就要重写onMeasure()方法。给View在wrap_content属性下设置默认大小。不设置的话就是整个父组件大小。
- 15 .自定义控件时为什么要重写onMeasure()方法?
view:为了处理在wrap_fill情况下的,组件大小
viewGroup:对子View进行遍历测量,来处理wrap_fill情况下自身的大小。
- 16 .项目优化?
分为两部分,布局优化和内存优化
布局优化:
1)16ms绘制完成一个布局,会感觉流畅。
2)避免过度绘制浪费cpu和gpu资源。检测工具“Enable GPU overdraw”
3)优化布局层级
4)合理使用include,viewStub,merge
5)在theme中添加android:windowbackground="null";减少背景层级的绘制
6)使用9patch图片
内存优化:
1)bitmap的优化
2)代码优化,使用静态检测
- 17 . hash算法为什么存取速度快?
它与线性表,树,图等结构不同,数据元素不存在逻辑关系,它只通过关键字与内存地址有关联。
散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key 对应一个存储位置f (key)。查找时,根据这个确定的对应关系找到给定值key 的映射f (key) ,若查找集合中存在这个记录,则必定在f (key) 的位置上。这里我们把这种对应关系f 称为散列函数, 又称为哈希(Hash) 函数。
- 18 . List和Set的区别?
List:是顺序表,可以存放相同元素。
Set:不可以存放相同元素。
- 19 . 通过什么办法保证Set列表中存放的元素是唯一的?
重写 hashcode()和equal()方法。
- 20 .Set接口的实现有哪些?他们有什么区别?
HashSet : 散列表存储,高效读取。
TreeSet:按照比较结果升序保存对象。元素必须实现Comparable接口。
LinkedHashSet:按照添加顺序保存对象。
- 21 .TreeSet是怎么对其中的元素进行排序的?
两种办法 自然排序和比较器排序。
自然排序:存放对象实现Comparerable接口 ,并且重写compareTo方法。
比较器排序:在TreeSet的构造函数中实现Comparator接口,重写compare方法。
参考:http://blog.csdn.net/xiaofei__/article/details/53138681
- 22 .List接口的实现有哪些?他们的比较?
ArrayList:擅长读取(线性表结构)
LinkedList:擅长插入和删除(链式存储结构)
- 23 .什么时候需要重写hashcode和equal()方法?
当使用散列数据结构时(HashSet,HashMap等)。
两个对象是否相等的规则是:
.1)判断两个对象的hashCode是否相等
如果不相等,认为两个对象也不相等,完毕,如果相等,转入2
.2)判断两个对象用equals运算是否相等
如果不相等,认为两个对象也不相等
如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
参考:http://blog.csdn.net/liushuai_ly/article/details/8197508
- 24 .怎么程序一个好的程序?
1.健壮性
2.可扩展性
3.容错性
4.稳定性
5.可以从错误中恢复通过异常处理
- 25 .异常处理的模型?
分为终止模型和恢复模型。
终止模型:抛出异常不做处理。
恢复模型:把try块放在while循环里,这样就不断的进入try块,直到得到满意的结果。
- 26 .对象的创建和销毁优化?
1)使用静态工厂方法代替构造器创建实例。这样不必在每次调用他们的时候都创建新的对象了。
2)多参数构造器时,使用建造者模式来创建对象。容易阅读。
3)使用弱引用来处理缓存对象(有些抽象,可以网上查询)
- 27 .怎么停止一个线程?
通过设置标准位。
- 28 .怎么处理滑动冲突?
可以通过外部拦截法,重写父组件的onInterceptTouchEvent()方法,处理滚动事件,当x大于y的时候,返回true,对事件进行消费。其他情况下返回false就行了。
- 29 .怎么提升app的启动速度?
在 android monitors 中点击cup模块中的小闹钟开始,再次点击停止。通过使用traceview可以得到哪些业务导致耗时操作。第三方初始化工作导致。
将第三方初始化工作放到服务中IntentService。
- 30 .android中属性动画和补间动画的区别?
补间动画只是支持对View进行移动、缩放、旋转和淡入淡出的操作,如果一旦需求超出了这四种操作,补间动画就无能为力了,比如改变一个View的宽度。
补间动画还有一个最大的缺陷,就是它只是改变了View的显示效果而已,并不会真正的改变View的属性。具体来说,例如屏幕左上角有一个Button,使用补间动画将其移动到右下角,此刻你去点击右下角的Button,它是绝对不会响应点击事件的,因此其作用区域依然还在左上角。只不过是补间动画将其绘制在右下角而已。
- 31 .android提供的缓存策略是什么?
LruCache:内存缓存类
DiskLruCache:存储缓存类
- 32.SlidingDrawer的使用?
- 33.Activity给Fragment传参数的方法?
public static SellCarClueFragment getInstance(String clueproper) {
SellCarClueFragment sellCarClueFragment = new SellCarClueFragment();
Bundle bundle = new Bundle();
bundle.putString("clueproper",clueproper);
sellCarClueFragment.setArguments(bundle);
return sellCarClueFragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if(getArguments()!=null){
mClueproper = getArguments().getString("clueproper");
}
return super.onCreateView(inflater, container, savedInstanceState);
}
- 1.怎么加速布局的绘制过程?
android3.0引入了硬件加速,他可以不用遍历整个ViewTree来进行重绘,只重绘改变了的组件。
传统的是通过draw()或者invalidate()方法通知屏幕刷新。
硬件加速的是将draw()方法里要绘制的图形放入DisplayList中,当这个ViewTree的DisplayList全部记录完成后,通过RootView中的DisplayList把改变的View,从新绘制。
分成四个级别:Appliction,Activity,Window,View
- 34.HashMap怎么根据Value删除一项?
- 35.RecycleView局部刷新?
1.notifyDataSetChanged()
2.notifyItemChanged(int postion)
- 36.HorizontalScrollView与SeekBar冲突,怎么解决?
主要原因是HorizontalScrollView拦截了水平滑动的事件,你虽然修改了onTouchEvent,但是事件还是会被拦截。关于解决,给你提供两个方向:
1、你可以重写onInterceptTouchEvent,判断当前触摸的位置如果是SeekBar则不拦截;
2、在SeekBar的父容器中,进行判断,如果当然触摸是SeekBar,则请求不被拦截 getParent().requestDisallowInterceptTouchEvent(true);
@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
getParent().requestDisallowInterceptTouchEvent(true);
return super.onInterceptTouchEvent(ev);
}
- 37.虚拟机
1)程序计数器(安全):当前线程所执行的字节码的行号指示器。
为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
2)虚拟机栈(安全):它的生命周期与线程相同。
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个 栈帧 用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
也就是说,栈是由一个个栈帧组成。
3)本地方法栈(安全):给虚拟机栈的功能差不多
4)堆(不安全):Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”
5)方法区(不安全):方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。很多人都更愿意把方法区称为“永久代”。
6)运行时常量池(不安全):是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用
- 38.在虚拟机中,对象的创建是怎样一个过程呢?
虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。
分配内存两种方式,指针碰撞和空闲列表。
选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。
39.类加载过程:
http://blog.csdn.net/hmzdbql/article/details/809717240 .Map的分类
1.HashMap:高速存取
2.LinkedHashMap:按照插入顺序进行保存
3.TreeMap:可以根据键进行排序
- 41 .可以向静态方法中传入Activity的上下文吗?
分成两个情况处理:
public class A{
public static a(Activity activity){
// do something
}
}
public class B{
private static Activity mActivity;
public static b(Activity activity){
mActivity = activity;
// do something
}
}
A中的静态方法a,传入了一个Activity对象,然后方法结束,Activity的引用activity生命周期结束,这样不会造成泄露,没问题。
B中的静态方法b,传入一个Activity对象,然后B的成员变量mActivity接收了这个引用。这个静态成员变量会一直存在在进程中,这样就会造成内存泄露。
如果 class B 是一个静态内部类,非要持有 activity 的引用的话,可以考虑弱引用。
static class B {
private WeakReference ref;
public void setRef(Activity activity) {
this.ref = new WeakReference<>(activity);
}
public void doSomething(){
if (ref.get() != null){
ref.get().doSomething();
}
}
}
- 42 .类在jvm的是怎样运行的?
/**
* 线程私有的:
* 程序计数器:代码行号指示器
* JVM栈 :每一个方法执行时都会创建一个栈帧,用来保存局部变量+对象引用
* Native栈 :处理底层本地方法
*
* 线程共享的:
* 堆 : new 出来的对象(包括成员变量,不包括成员方法)+ 数组
* 方法区 (内部包含常量池):类信息,常量,静态变量 ,方法,编译后代码
*/
public class JvmUtil {
private String name; //堆中
//getName()进入方法区的常量池中
private void getName(){
String name; //局部变量 栈中
/**
* new SplashActivity() 堆中
* activity 栈中
*/
//当执行到这行时,程序计数器进行保存行号
SplashActivity activity = new SplashActivity();
}
}
- 43 .怎么检查内存泄漏问题?
http://m.blog.csdn.net/kong_gu_you_lan/article/details/74469041
- 44 .什么是线性表?
线性表(元素关系一对一):
顺序存储结构:
1)存储地址连续。
2)时间性能:查找O(1)、插入和删除O(n)。
3)空间性能:需要预分配存储空间,分大了浪费,小了容易发生上溢。
链式存储结构:
1)任意的存储单元。
2)时间性能:查找O(n)、插入和删除O(1)。
3)空间性能:不需要分配存储空间,只要有就可以分配,元素个数不受限制