2018年Android面试题整理
这是我近段时间收集的面试题,献给打算年后找工作的同学们。文中涉及的知识比较广也可能比较零散,并且一些较为基础的知识我都略去了(比如Android四大组件是什么这类问题),有些我附上了自己的理解,有些附上了详细的相关文章链接。大家挑自己感兴趣的内容查看即可,后期我也会继续不断补充。
基础组件篇
横竖屏切换时Activity的生命周期变化?
分两种情况,Activity并不总是被kill然后recreate,取决于用户是否配置了Android:ConfigChanges, 具体如下。
1.如果自己没有配置android:ConfigChanges,这时默认让系统处理,就会重建Activity,此时Activity的生命周期会走一遍。
onSaveInstanceState() 与onRestoreIntanceState()
资源相关的系统配置发生改变或者资源不足:例如屏幕旋转,当前Activity会销毁,并且在onStop之前回调onSaveInstanceState保存数据,在重新创建Activity的时候在onStart之后回调onRestoreInstanceState。
其中Bundle数据会传到onCreate(不一定有数据)和onRestoreInstanceState(一定有数据)。SO上有人说这个onSaveInstanceState函数只在屏幕需旋转或android系统由于释放资源需要才会调用,而用户或者程序员主动去销毁一个Activity的时候不会调用,来保存界面信息。如代码中finish()或用户按下back,不会回调。
2.如果设置 android:configChanges="orientation|keyboardHidden|screenSize">
,此时Activity的生命周期不会重走一遍,Activity不会重建,只会回调onConfigurationChanged方法。因此用户可以实现此方法,
具体可以参考官方链接的如下部分: https://developer.android.com/guide/topics/resources/runtime-changes
自行处理配置变更
如果应用在特定配置变更期间无需更新资源,并且因性能限制您需要尽量避免重启,则可声明 Activity 将自行处理配置变更,这样可以阻止系统重启 Activity。
注:自行处理配置变更可能导致备用资源的使用更为困难,因为系统不会为您自动应用这些资源。 只能在您必须避免 Activity 因配置变更而重启这一万般无奈的情况下,才考虑采用自行处理配置变更这种方法,而且对于大多数应用并不建议使用此方法。
要声明由 Activity 处理配置变更,请在清单文件中编辑相应的 <activity>
元素,以包含 android:configChanges
属性以及代表要处理的配置的值。android:configChanges
属性的文档中列出了该属性的可能值(最常用的值包括 "orientation"
和 "keyboardHidden"
,分别用于避免因屏幕方向和可用键盘改变而导致重启)。您可以在该属性中声明多个配置值,方法是用管道 |
字符分隔这些配置值。
例如,以下清单文件代码声明的 Activity 可同时处理屏幕方向变更和键盘可用性变更:
android:configChanges="orientation|keyboardHidden" android:label="@string/app_name">
现在,当其中一个配置发生变化时,MyActivity
不会重启。相反,MyActivity
会收到对 onConfigurationChanged()
的调用。向此方法传递 Configuration
对象指定新设备配置。您可以通过读取Configuration
中的字段,确定新配置,然后通过更新界面中使用的资源进行适当的更改。调用此方法时,Activity 的 Resources
对象会相应地进行更新,以根据新配置返回资源,这样,您就能够在系统不重启 Activity 的情况下轻松重置 UI 的元素。
注意:从 Android 3.2(API 级别 13)开始,当设备在纵向和横向之间切换时,“屏幕尺寸”也会发生变化。因此,在开发针对 API 级别 13 或更高版本(正如 minSdkVersion
和 targetSdkVersion
属性中所声明)的应用时,若要避免由于设备方向改变而导致运行时重启,则除了 "orientation"
值以外,您还必须添加 "screenSize"
值。 也就是说,您必须声明 android:configChanges="orientation|screenSize"
。但是,如果您的应用面向 API 级别 12 或更低版本,则 Activity 始终会自行处理此配置变更(即便是在 Android 3.2 或更高版本的设备上运行,此配置变更也不会重启 Activity)。
例如,以下 onConfigurationChanged()
实现检查当前设备方向:
public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Checks the orientation of the screen if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); } }
Configuration
对象代表所有当前配置,而不仅仅是已经变更的配置。大多数时候,您并不在意配置具体发生了哪些变更,而且您可以轻松地重新分配所有资源,为您正在处理的配置提供备用资源。 例如,由于 Resources
对象现已更新,因此您可以通过 setImageResource()
重置任何 ImageView
,并且使用适合于新配置的资源(如提供资源中所述)。
请注意,Configuration
字段中的值是与 Configuration
类中的特定常量匹配的整型数。有关要对每个字段使用哪些常量的文档,请参阅 Configuration
参考文档中的相应字段。
请谨记:在声明由 Activity 处理配置变更时,您有责任重置要为其提供备用资源的所有元素。 如果您声明由 Activity 处理方向变更,而且有些图像应该在横向和纵向之间切换,则必须在 onConfigurationChanged()
期间将每个资源重新分配给每个元素。
如果无需基于这些配置变更更新应用,则可不用实现 onConfigurationChanged()
。在这种情况下,仍将使用在配置变更之前用到的所有资源,只是您无需重启 Activity。 但是,应用应该始终能够在保持之前状态完好的情况下关闭和重启,因此您不得试图通过此方法来逃避在正常 Activity 生命周期期间保持您的应用状态。 这不仅仅是因为还存在其他一些无法禁止重启应用的配置变更,还因为有些事件必须由您处理,例如用户离开应用,而在用户返回应用之前该应用已被销毁。
如需了解有关您可以在 Activity 中处理哪些配置变更的详细信息,请参阅 android:configChanges
文档和 Configuration
类。
activity的startActivity和context的startActivity区别
这个看一下它的官方文档就清楚了:
startActivity added in API level 16
public abstract void startActivity (Intent intent, Bundle options)
Launch a new activity. You will not receive any information about when the activity exits.
Note that if this method is being called from outside of an Activity
Context, then the Intent must include the Intent.FLAG_ACTIVITY_NEW_TASK
launch flag. This is because, without being started from an existing Activity, there is no existing task in which to place the new activity and thus it needs to be placed in its own separate task. 就是因为每个Activity都需要放在某一个Task里面。
This method throws ActivityNotFoundException
if there was no Activity found to run the given Intent.
(1)从Activity中启动新的Activity时可以直接mContext.startActivity(intent)
就好,这个新的Activity和原Activity属于同一个Task的任务栈,back stack。
(2)如果从其他Context中启动Activity则必须给intent设置Flag:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ;
mContext.startActivity(intent);
以下代码演示如何从一个Activity启动另一个Activity: Intent intentB = new Intent(ActivityC.this, ActivityB.class); intentB.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); ActivityC.this.startActivity(intentB);
介绍下Android应用程序启动过程
整个应用程序的启动过程要执行很多步骤,但是整体来看,主要分为以下五个阶段:
一. :Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity;
二.:ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
三.:Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行;
四. :ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
五 :ActivityManagerService通过Binder进程间通信机制通知ActivityThread,现在一切准备就绪,它可以真正执行Activity的启动操作了。
复制代码
相关文章:Android应用程序启动过程源代码分析
如何保证Service不被杀死?
- 提供进程优先级,降低进程被杀死的概率
方法一:监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,在用户解锁时将 Activity 销毁掉。
方法二:启动前台service。
方法三:提升service优先级:
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。 - 在进程被杀死后,进行拉活
方法一:注册高频率广播接收器,唤起进程。如网络变化,解锁屏幕,开机等
方法二:双进程相互唤起。
方法三:依靠系统唤起。
方法四:onDestroy方法里重启service:service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service; - 依靠第三方
根据终端不同,在小米手机(包括 MIUI)接入小米推送、华为手机接入华为推送;其他手机可以考虑接入腾讯信鸽或极光推送与小米推送做 A/B Test。
简述下Acitivty任务栈和使用方法
任务栈是一种后进先出的结构。位于栈顶的Activity处于焦点状态,当按下back按钮的时候,栈内的Activity会一个一个的出栈,并且调用其onDestory()方法。如果栈内没有Activity,那么系统就会回收这个栈,每个APP默认只有一个栈,以APP的包名来命名.
1、standard:默认模式:每次启动都会创建一个新的activity对象,放到目标任务栈中
2、singleTop:判断当前的任务栈顶是否存在相同的activity对象,如果存在,则直接使用,如果不存在,那么创建新的activity对象放入栈中
3、singleTask:在任务栈中会判断是否存在相同的activity,如果存在,那么会清除该activity之上的其他activity对象显示,如果不存在,则会创建一个新的activity放入栈顶
4、singleIntance:会在一个新的任务栈中创建activity,并且该任务栈种只允许存在一个activity实例,其他调用该activity的组件会直接使用该任务栈种的activity对象
方法一:
使用android:launchMode="standard|singleInstance|single Task|singleTop"来控制Acivity任务栈。
方法二:
Intent Flags:
Intent intent=new Intent();
intent.setClass(MainActivity.this, MainActivity2.class);
intent.addFlags(Intent. FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
复制代码
Flags有很多,比如:
Intent.FLAG_ACTIVITY_NEW_TASK 相当于singleTask
Intent. FLAG_ACTIVITY_CLEAR_TOP 相当于singleTop
set up an activity as the entry point for a task by giving it an intent filter
<activity ... > <intent-filter ... > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> ... </activity>
相关文章:Android总结篇系列:Activity Intent Flags及Task相关属性
获取系统进程信息
package com.example.test1;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.os.Debug;
public class AppInformation {
private ActivityManager activityManager = null;
public AppInformation(Context context) {
this.activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
}
public List getRunningTaskInfo() {
System.out.println("getRunningServiceInfo()...");
List taskList = activityManager.getRunningTasks(30);
for (int i = 0; i < taskList.size(); i++) {
RunningTaskInfo taskInfo = (RunningTaskInfo) taskList.get(i);
String packageName = taskInfo.baseActivity.getPackageName();
System.out.println("package name: " + packageName);
}
return taskList;
}
}
Context相关问题
Activity和Service以及Application的Context是不一样的,Activity继承自ContextThemeWraper.其他的继承自ContextWrapper.
每一个Activity和Service以及Application的Context都是一个新的ContextImpl对象
getApplication()用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法.
getApplicationContext()比getApplication()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。
Context的数量等于Activity的个数 + Service的个数 + 1,这个1为Application.
那Broadcast Receiver,Content Provider呢?Broadcast Receiver,Content Provider并不是Context的子类,他们所持有的Context都是其他地方传过去的,所以并不计入Context总数。
怎么在Service中创建Dialog对话框
1.在我们取得Dialog对象后,需给它设置类型,即:
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
2.在Manifest中加上权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
View篇
非UI线程可以更新UI吗?
可以
当访问UI时,ViewRootImpl会调用checkThread
方法去检查当前访问UI的线程是哪个,如果不是UI线程则会抛出异常
执行onCreate方法的那个时候ViewRootImpl还没创建,无法去检查当前线程.ViewRootImpl的创建在onResume方法回调之后.
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
复制代码
非UI线程是可以刷新UI的,前提是它要拥有自己的ViewRoot,即更新UI的线程和创建ViewRoot是同一个,或者在执行checkThread()
前更新UI.
相关文章:Android子线程真的不能更新UI么
解决ScrollView嵌套ListView和GridView冲突的方法
重写ListView的onMeasure方法,来自定义高度:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
复制代码
主要考察对MeasureSpec的三种模式的理解,相关文章.
自定义View优化策略
为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。
另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。
如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。
线程篇
Handler、Message、Looper、MessageQueue
一、相关概念的解释
主线程(UI线程)
定义:当程序第一次启动时,Android会同时启动一条主线程(Main Thread)
作用:主线程主要负责处理与UI相关的事件
Message(消息)
定义:Handler接收和处理的消息对象(Bean对象)
作用:通信时相关信息的存放和传递
ThreadLocal
定义:ThreadLocal是线程内部的存储类,通过它可以实现在每个线程中存储自己的私有数据。即数据存储以后,只能在指定的线程中获取这个存储的对象,而其它线程则不能获取到当前线程存储的这个对象。
作用:负责存储和获取本线程的Looper
MessageQueue(消息队列)
定义:采用单链表的数据结构来存储消息列表
作用:用来存放通过Handler发过来的Message,按照先进先出执行
Handler(处理者)
定义:Message的主要处理者
作用:负责发送Message到消息队列&处理Looper分派过来的Message
Looper(循环器)
定义:扮演Message Queue和Handler之间桥梁的角色
作用:
消息循环:循环取出Message Queue的Message
消息派发:将取出的Message交付给相应的Handler
2、自己画下图解
3、Handler发送消息有哪几种方式?
一、sendMessage(Message msg)
二、post(Ruunable r)
4、Handler处理消息有哪几种方式?
这个直接看dispatchMessage()
源码:
public void dispatchMessage(Message msg){
if (msg.callback != null) {
//1. post()方法的处理方法
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//2. sendMessage()方法的处理方法
handleMessage(msg);
}
}
//1. post()方法的最终处理方法
private static void handleCallback(Message message){
message.callback.run();
}
//2. sendMessage()方法的最终处理方法
public void handleMessage(Message msg){
}
复制代码
5.Message、Handler、MessageQueue、Looper的之间的关系?
首先,是这个MessagQueue,MessageQueue是一个消息队列,它可以存储Handler发送过来的消息,其内部提供了进队和出队的方法来管理这个消息队列,其出队和进队的原理是采用单链表的数据结构进行插入和删除的,即enqueueMessage()方法和next()方法。这里提到的Message,其实就是一个Bean对象,里面的属性用来记录Message的各种信息。
然后,是这个Looper,Looper是一个循环器,它可以循环的取出MessageQueue中的Message,其内部提供了Looper的初始化和循环出去Message的方法,即prepare()方法和loop()方法。在prepare()方法中,Looper会关联一个MessageQueue,而且将Looper存进一个ThreadLocal中,在loop()方法中,通过ThreadLocal取出Looper,使用MessageQueue的next()方法取出Message后,判断Message是否为空,如果是则Looper阻塞,如果不是,则通过dispatchMessage()方法分发该Message到Handler中,而Handler执行handlerMessage()方法,由于handlerMessage()方法是个空方法,这也是为什么需要在Handler中重写handlerMessage()方法的原因。这里要注意的是Looper只能在一个线程中只能存在一个。这里提到的ThreadLocal,其实就是一个对象,用来在不同线程中存放对应线程的Looper。
最后,是这个Handler,Handler是Looper和MessageQueue的桥梁,Handler内部提供了发送Message的一系列方法,最终会通过MessageQueue的enqueueMessage()方法将Message存进MessageQueue中。我们平时可以直接在主线程中使用Handler,那是因为在应用程序启动时,在入口的main方法中已经默认为我们创建好了Looper。
相关文章:blog.csdn.net/qq_30379689…
6.为什么在子线程中创建Handler会抛异常?
Handler的工作是依赖于Looper的,而Looper(与消息队列)又是属于某一个线程(ThreadLocal是线程内部的数据存储类,通过它可以在指定线程中存储数据,其他线程则无法获取到),其他线程不能访问。因此Handler就是间接跟线程是绑定在一起了。因此要使用Handler必须要保证Handler所创建的线程中有Looper对象并且启动循环。因为子线程中默认是没有Looper的,所以会报错。
正确的使用方法是:
private final class WorkThread extends Thread{
private Handler mHandler;
public Handler getHandler(){
return mHandler;
}
public void quit(){
mHandler.getLooper().quit();
}
@Override
public void run(){
super.run();
//创建该线程对应的Looper,
// 内部实现
// 1。new Looper()
// 2。将1步中的lopper 放在ThreadLocal里,ThreadLocal是保存数据的,主要应用场景是:线程间数据互不影响的情况
// 3。在1步中的Looper的构造函数中new MessageQueue();
//其实就是创建了该线程对用的Looper,Looper里创建MessageQueue来实现消息机制
//对消息机制不懂得同学可以查阅资料,网上很多也讲的很不错。
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg){
super.handleMessage(msg);
Log.d("WorkThread", (Looper.getMainLooper() == Looper.myLooper()) + "," + msg.what);
}
};
//开启消息的死循环处理即:dispatchMessage
Looper.loop();
//注意这3个的顺序不能颠倒
Log.d("WorkThread", "end");
}
}
复制代码
HandlerThread
1、HandlerThread作用
当系统有多个耗时任务需要执行时,每个任务都会开启一个新线程去执行耗时任务,这样会导致系统多次创建和销毁线程,从而影响性能。为了解决这一问题,Google提供了HandlerThread,HandlerThread是在线程中创建一个Looper循环器,让Looper轮询消息队列,当有耗时任务进入队列时,则不需要开启新线程,在原有的线程中执行耗时任务即可,否则线程阻塞。
2、HanlderThread的优缺点
- HandlerThread本质上是一个线程类,它继承了Thread;
- HandlerThread有自己的内部Looper对象,可以进行looper循环;
- 通过获取HandlerThread的looper对象传递给Handler对象,可以在
handleMessage()
方法中执行异步任务。 - 创建HandlerThread后必须先调用
HandlerThread.start()
方法,Thread会先调用run方法,创建Looper对象。 - HandlerThread优点是异步不会堵塞,减少对性能的消耗
- HandlerThread缺点是不能同时继续进行多任务处理,需要等待进行处理,处理效率较低
- HandlerThread与线程池不同,HandlerThread是一个串行队列,背后只有一个线程。
相关文章:Android 多线程之IntentService 完全详解
IntentService
- 它本质是一种特殊的Service,继承自Service并且本身就是一个抽象类
- 它可以用于在后台执行耗时的异步任务,当任务完成后会自动停止
- 它拥有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务
它内部通过HandlerThread和Handler实现异步操作 - 创建IntentService时,只需实现onHandleIntent和构造方法,onHandleIntent为异步方法,可以执行耗时操作
- 即使我们多次启动IntentService,但IntentService的实例只有一个,这跟传统的Service是一样的,最终IntentService会去调用onHandleIntent执行异步任务。
- 当任务完成后,IntentService会自动停止,而不需要手动调用
stopSelf()
。另外,可以多次启动IntentService,每个耗时操作都会以工作队列的方式在IntentService
中onHandlerIntent()
回调方法中执行,并且每次只会执行一个工作线程。
相关文章:Android 多线程之IntentService 完全详解
AsyncTask
1、AsyncTask是什么
AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并主线程中更新UI,通过AsyncTask可以更加方便执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。
2、AsyncTask使用方法
三个参数
Params:表示后台任务执行时的参数类型,该参数会传给AysncTask的doInBackground()方法
Progress:表示后台任务的执行进度的参数类型,该参数会作为onProgressUpdate()方法的参数
Result:表示后台任务的返回结果的参数类型,该参数会作为onPostExecute()方法的参数
五个方法
onPreExecute():异步任务开启之前回调,在主线程中执行
doInBackground():执行异步任务,在线程池中执行
onProgressUpdate():当doInBackground中调用publishProgress时回调,在主线程中执行
onPostExecute():在异步任务执行之后回调,在主线程中执行
onCancelled():在异步任务被取消时回调
3、AsyncTask引起的内存泄漏
原因:非静态内部类持有外部类的匿名引用,导致Activity无法释放
解决:
AsyncTask内部持有外部Activity的弱引用
AsyncTask改为静态内部类
Activity的onDestory()中调用AsyncTask.cancel()
4.结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
5、AsyncTask并行or串行
AsyncTask在Android 2.3之前默认采用并行执行任务,AsyncTask在Android 2.3之后默认采用串行执行任务
如果需要在Android 2.3之后采用并行执行任务,可以调用AsyncTask的executeOnExecutor();
6.AsyncTask内部的线程池
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
sDefaultExecutor
是SerialExecutor
的一个实例,而且它是个静态变量。也就是说,一个进程里面所有AsyncTask对象都共享同一个SerialExecutor
对象。
相关文章:android多线程-AsyncTask之工作原理深入解析
一些面试心经
一般情况下第一轮都是基础面试,需要扎实的基础
最常用的Android 基础知识
Java 基础知识
了解一些 常用东西的原理,例如:handler, thread 等
项目中的技术点
第二轮的时候需要了解更深层次的东西
Android 事件分发机制原理
Android 绘图机制原理
WindowManager 的相关知识
进程间传输方式
Java 内存管理机制
一些常用的 list,map 原理,以及子类之间的差别
能进入第三轮基本没什么问题,但是要注意以下问题
该轮一般是 老大或者部门负责人,问的问题一般都看 深度与广度
当问及薪水的时候,要说一个合适的,小公司随意,大公司一定要慎重,当心里没底的时候,可以告诉对方,让对方给一个合理的薪资。一般都是在原工资基础之上增长,听猎头说一般涨幅都在15%-30%,超 NB 的可以要30%及以上,如果感觉自己还不错的,挺厉害的,建议最高20%,一般人就定在15% 左右最靠谱。公司内部一般有一套机制,根据公司情况而定。
我们的面试原则就是拿到合理薪资,得到 offer
个人发展情况,这个问题很难回答,如果和公司方向不符合,极有可能和公司无缘。建议多试探性的问问公司缺少什么,你能否给予公司对应的东西。当然对于有自我追求的人,那可以放心大胆的提。我的方向就是架构师,哈哈哈,挺极端的,别学我哦。我感觉选择都是双向的,因此我知道自己需要的是什么。
你最擅长什么UI 还是其他什么?这个问题更不好回答。你要说你擅长 UI,是不是意味着你其他能力就不行?虽然我不知道面试官的用意,但是我能感觉到,这个问题不是那么好回答,我会回答说自己都行,来什么业务接什么需求。可能回答不太好,总之和公司的职位吻合就行,这样总不至于出错吧。
摘自文章:一个五年Android开发者百度、阿里、聚美、映客的面试心经
简历模板推荐:
更多面试题库:
www.jackywang.tech/AndroidInte…
github.com/AweiLoveAnd…
github.com/hadyang/int…
jingbin.me/2017/02/20/…
github.com/Freelander/…
www.jianshu.com/p/1d3a2227f…
github.com/stormzhang/…
www.zhihu.com/question/37…
Android 2018 最新面试题(3-5年经验个人面试经历)
网站
错了吧
评论
21天前
评论
2月前
1条评论
2月前
1条评论
4月前
2条评论
5月前