欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发中常见面试题解析

程序员文章站 2022-05-31 08:20:18
一、自定义view的流程 记清楚函数调用的顺序才能准确地进行调用。 根据调用链,可将整个绘制过程分为三部分:measure - layout - draw 一、定义自定义vi...
一、自定义view的流程

记清楚函数调用的顺序才能准确地进行调用。

根据调用链,可将整个绘制过程分为三部分:measure - layout - draw

一、定义自定义view的类。
为了创建点击可切换的形状的自定义view,我们继承view,编写构造方法。实现三个构造方法,最终调用三个参数的构造方法。

public class customview extends view {

    public customview(context context) {
        this(context, null);
    }

    public customview(context context, attributeset attrs) {
        this(context, attrs, 0);
    }

    public customview(context context, attributeset attrs, int defstyle) {
        super(context, attrs, defstyle);
    }
}
二、把自定义view加入到layout中
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    

 第一步:当activity启动的时候,触发初始化view过程的是由window对象的decorview调用view(具体怎样从xml中读取是用layoutinflater.from(context).inflate)对象的 public final void measure(int widthmeasurespec, int heightmeasurespec)方法开始的,这个方法是final类型的,也就是所有的子类都不能继承该方法,保证android初始化view的原理不变。具体参数类值,后面会介绍。


   第二步:view的measure方法 onmeasure(widthmeasurespec, heightmeasurespec),该方法进行实质性的view大小计算。注意:view的大小是有父view和自己的大小决定的,而不是单一决定的。这也就是为什么viewgroup的子类会重新该方法,比如linearlayout等。因为他们要计算自己和子view的大小。view基类有自己的实现,只是设置大小。其实根据源码来看,measure的过程本质上就是把match_parent和wrap_content转换为实际大小


    第三步:当measure结束时,回到decorview,计算大小计算好了,那么就开始布局了,开始调用view的 public final void layout(int l, int t, int r, int b),该还是也是final类型的,目的和measure方法一样。layout方法内部会调用onlayout(int l, int t, int r, int b )方法,二viewgroup将此方法abstract的了,所以我们继承viewgroup的时候,需要重新该方法。该方法的本质是通过measure计算好的大小,计算出view在屏幕上的坐标点

   第四步:measure过了,layout过了,那么就要开始绘制到屏幕上了,所以开始调用view的public void draw(canvas canvas)方法,此时方法不是final了,原因是程序员可以自己画,内部会调用ondraw,我们经常需要重写的方法。
六、servise的生命周期,有几种servise

 

开启一个服务有两种方法,第一种为startsevice,第二种则是bindservice。

//第一种启动式

 

btn1.setonclicklistener(newview.onclicklistener(){

@override

publicvoidonclick(viewv){

intentit=newintent(main.this,myservice.class);

startservice(it);

//bindservice(it,conn,service.bind_auto_create);

}

}); //第二种绑定式

 

privatemyserviceservice;

publicserviceconnectionconn=newserviceconnection(){

 

@override

publicvoidonserviceconnected(componentnamename,ibinderservice){

log.v("tag","onserviceconnected"+",componentname:"+name);

main.this.service=((myservice.ibinderimpl)service).getinstance();

}

 

@override

publicvoidonservicedisconnected(componentnamename){

log.v("tag","onservicedisconnected");

main.this.service=null;

}

 

};
//这是servise的代码

publicclassmyserviceextendsservice{



@override

publicvoidoncreate(){

super.oncreate();

log.v("tag","服务:oncreate");

 

}

@override

publicvoidondestroy(){

super.oncreate();

log.v("tag","服务:ondestroy");

}

@override

publicintonstartcommand(intentintent,intflags,intstartid){

log.v("tag","服务:onstartcommand");

returnsuper.onstartcommand(intent,flags,startid);

}

 

@override

publicvoidonrebind(intentit){

super.onrebind(it);

log.v("tag","服务:onrebind");

}

 

@override

publicbooleanonunbind(intentit){

log.v("tag","服务:onunbind");

returnsuper.onunbind(it);



}



publicclassibinderimplextendsbinder{

publicmyservicegetinstance(){

returnmyservice.this;

}

};

@override

publicibinderonbind(intentintent){

log.v("tag","服务:onbind");

returnnewibinderimpl();

}

 

} 九.安卓如何处理异步 1.handler 2.thread 十、app的优化,内存,绘制,oom. - 响应时间(response time)
- 界面卡顿(anr)
- 耗内存(memory)
- 内存泄露(out of memory)

界面卡顿

anr表示”应用程序无响应”,这个是需要我们避免发生的事情,出现这个异常的原因:
- 主线程 (“事件处理线程” / “ui线程”) 在5秒内没有响应输入事件
- broadcastreceiver在10秒内没有执行完毕

导致anr的原因有很多,一般情况就是在ui线程做了耗时的操作,例如”网络请求”、操作。

那么如何避免?
- ui线程只做界面刷新,不做任何耗时操作,耗时操作放在子线程来做
- 可以使用thread+handle或者asynctask来进行逻辑处理