12月22日的android面试总结

96 阅读1分钟

主要有这么几个问题

1.kotlin foreach如何跳出当前循环

答:在foreach前面打标签。使用return@标签的方式。

2.广播的两种注册方式的区别?

答:广播主要有两种方式去注册。一种是静态广播,一种是动态广播。

静态方式是指在mainfest.xml里去注册,然后在安装的时候,是由PackageManagerService去注册。

动态的话则是使用registerReceiver的方式来注册。

动态广播的优先级>静态广播,也就是说动态广播接收的更快。 动态广播的生命周期和它的context有关。静态广播则是常驻的。应用退出后仍然可以接收到。

一些特殊的广播,必须使用动态广播,静态不起效果。比如锁屏。

3.自定义viewGroup,使子view可以垂直排列,类似linearlayout。

答:这里注意两个方法就可以。

1.第一个方法是onMeasure()方法,这个方法是测绘自己的宽高。 在这个方法里,便利自己的子view,比较出最大宽度再加上paddingleft和paddingright,作为自己的宽度。然后把子view的高度相加,然后再加上paddingtop和paddingbottom作为自己的高度。最后调用setMeasureDimension(W,H)作为自己的宽高。代码如下:

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		//先定义自己的宽高初始值
		int measureWidth = 0;
		int measureHeight = 0;

		int count = getChildCount();
		for(int i=0; i < count; ++i) {
			View v = getChildViewAt(i);
			if(v.visibility() != View.Gone) {
				//获取子view的宽高
				measureChild(v,widthMesaureSpec,widthMesureSpec);
				//取出最大宽度作为viewGroup的宽度
				mesasureWidth = Math.max(messasureWdith,v.getMesuareWidth);
				//把高度相加作为自己的高度
				measureHeight += v.getMeasureHeight();
			}
		}

		//加上padding
		mesuredWidth += getPaddingLef()+ getPaddingRight();
		mesauredHeight += getPaddingTop() + getPaddingBottom();

		//度量自己,调用setMeasureDimension()
		setMeasureDimension(measureWidth,measureHeight);
    }

2.第二个,就是onLayout()方法。这个方法的作用就是布局自己的子view.也就是说画一些框框,放置自己的子view.

    protected void onLayout(boolean changed, int l, int t, int r, int b) {
		//获取子view的数量
		int count = getChildCount();
		for(int i=0; i< count;++i) {
			View v = getChildAt(i);
			if (v.getVisibility() != View.Gone)
			{
				int childWidth = v.getMeasureWidth();
				int childHeight = v.getMeasuredHeight();

				//开始摆放
				v.layout(l,t,l+childWidht,t+childHeight);
                //注意,这里主要是改变他的top值
				t += childHeight;

			}
		}
    }

4.使用handler的时候,是怎么把Message放到messageQueue里面去的?

答:先说Handler的流程。 Handler.sendMessageAtTime()。在这个方法里会调用enqueueMessage(queue, msg, uptimeMillis)这个方法,这个方法里,会调用messageQueue的enqueueMessage(msg,time)方法,把Meessage放到mssageQueue队列里的。

到这里Handler就把消息发出去了。

接下来就是取消息。Looper从队列里取消息,就是调用Handler的dispatchMessage方法。

 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

大家从这个代码块里可以看出,当Message携带的操作是以Runnable形式存在的,就会用handleCallback,然后调用run方法。否则就会调用handlerMessag。我们通常都是继承handler重写这个方法,用来处理消息。

5.常见的内存泄漏,以及解决方案。

1.android特色的在activity中使用handler内部类。handler持有activity,handler又被Message持有,message又被messageQueue持有。当这个message还没有到执行时间的时候,activity进行销毁,却发现被持有销毁不了。解决:静态内部类的方式。或者使用虚引用。

2.匿名内部类。内部类默认持有外部类的对象。如果内部类执行了耗时操作,就会泄漏。

3.资源释放。比如数据库的打开和关闭,文件流的打开和关闭,还有bitmap等。我们要根据生命周期,去手动关闭。

4.注册了一些东西,在ondestroy的时候,要看看注册的时候干了什么,到关闭的时候有没有相应的资源需要关闭。

6.两个Activity,从A启动到B的生命周期?

答:onPauseA() -> onCreateB() -> onStartB() -> onResumeB() -> onStopA()

此时,如果再从B返回到A呢?

onPauseB() -> onReStartA() -> onstartA() -> onResumeA() -> onStopB() -> onDestroyB()